From d666a3d92cb5dd9844c29e5472db542de7b5ac9e Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Thu, 18 Nov 2010 08:43:09 -0800 Subject: ESC-154 ESC-155 ESC-156 Asset fetch requests wrapped to allow for measurements. Asset fetch enqueues, dequeues and completion times recorded to asset stats collector. Texture fetch operations (http and udp) recorded to asset stats collector. Stats collector time vallue switched from F32 to U64 which is the more common type in the viewer. Cross-thread mechanism introduced to communicate region changes and generate global statistics messages. Facility to deliver metrics via Capabilities sketched in but needs additional work. Documentation and diagrams added. --- indra/newview/llappviewer.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 333c92e50d..2e056238e4 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -190,6 +190,7 @@ #include "llparcel.h" #include "llavatariconctrl.h" #include "llgroupiconctrl.h" +#include "llviewerassetstats.h" // Include for security api initialization #include "llsecapi.h" @@ -332,6 +333,14 @@ static std::string gWindowTitle; LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ; +//---------------------------------------------------------------------------- +// Metrics logging control constants +//---------------------------------------------------------------------------- +static const F32 METRICS_INTERVAL_MIN = 300.0; +static const F32 METRICS_INTERVAL_MAX = 3600.0; +static const F32 METRICS_INTERVAL_DEFAULT = 600.0; + + void idle_afk_check() { // check idle timers @@ -656,6 +665,8 @@ bool LLAppViewer::init() LLCurl::initClass(); LLMachineID::init(); + LLViewerAssetStatsFF::init(); + initThreads(); writeSystemInfo(); @@ -1670,6 +1681,8 @@ bool LLAppViewer::cleanup() LLWatchdog::getInstance()->cleanup(); + LLViewerAssetStatsFF::cleanup(); + llinfos << "Shutting down message system" << llendflush; end_messaging_system(); @@ -3683,6 +3696,18 @@ void LLAppViewer::idle() gInventory.idleNotifyObservers(); } + // Metrics logging (LLViewerAssetStats, etc.) + { + static LLTimer report_interval; + + // *TODO: Add configuration controls for this + if (report_interval.getElapsedTimeF32() >= METRICS_INTERVAL_DEFAULT) + { + metricsIdle(! gDisconnected); + report_interval.reset(); + } + } + if (gDisconnected) { return; @@ -4525,3 +4550,92 @@ bool LLAppViewer::getMasterSystemAudioMute() { return gSavedSettings.getBOOL("MuteAudio"); } + +//---------------------------------------------------------------------------- +// Metrics-related methods (static and otherwise) +//---------------------------------------------------------------------------- + +/** + * LLViewerAssetStats collects data on a per-region (as defined by the agent's + * location) so we need to tell it about region changes which become a kind of + * hidden variable/global state in the collectors. For collectors not running + * on the main thread, we need to send a message to move the data over safely + * and cheaply (amortized over a run). + */ +void LLAppViewer::metricsUpdateRegion(const LLUUID & region_id) +{ + if (! region_id.isNull()) + { + LLViewerAssetStatsFF::set_region_main(region_id); + if (LLAppViewer::sTextureFetch) + { + // Send a region update message into 'thread1' to get the new region. + LLAppViewer::sTextureFetch->commandSetRegion(region_id); + } + else + { + // No 'thread1', a.k.a. TextureFetch, so update directly + LLViewerAssetStatsFF::set_region_thread1(region_id); + } + } +} + + +/** + * Attempts to start a multi-threaded metrics report to be sent back to + * the grid for consumption. + */ +void LLAppViewer::metricsIdle(bool enable_reporting) +{ + if (! gViewerAssetStatsMain) + return; + + std::string caps_url; + LLViewerRegion * regionp = gAgent.getRegion(); + if (regionp) + { + caps_url = regionp->getCapability("ViewerMetrics"); + caps_url = "http://localhost:80/putz/"; + } + + if (enable_reporting && regionp && ! caps_url.empty()) + { + // *NOTE: Pay attention here. LLSD's are not safe for thread sharing + // and their ownership is difficult to transfer across threads. We do + // it here by having only one reference (the new'd pointer) to the LLSD + // or any subtree of it. This pointer is then transfered to the other + // thread using correct thread logic. + + LLSD * envelope = new LLSD(LLSD::emptyMap()); + { + (*envelope)["session_id"] = gAgentSessionID; + (*envelope)["agent_id"] = gAgentID; + (*envelope)["regions"] = gViewerAssetStatsMain->asLLSD(); + } + + if (LLAppViewer::sTextureFetch) + { + // Send a report request into 'thread1' to get the rest of the data + // and have it sent to the stats collector. LLSD ownership transfers + // with this call. + LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, envelope); + envelope = 0; // transfer noted + } + else + { + // No 'thread1' so transfer doesn't happen and we need to clean up + delete envelope; + envelope = 0; + } + } + else + { + LLAppViewer::sTextureFetch->commandDataBreak(); + } + + // Reset even if we can't report. Rather than gather up a huge chunk of + // data, we'll keep to our sampling interval and retain the data + // resolution in time. + gViewerAssetStatsMain->reset(); +} + -- cgit v1.3 From a99db82e9b3ce25bf2745721b57f0259a770b26a Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Fri, 19 Nov 2010 15:14:40 -0800 Subject: ESC-155 Multi-threaded umbrella collector for stats aggregation Code complete with the intelligence to merge counts, mins, maxes and means with reasonable defences. Added QAMode controls to the viewer so that we can QA this more quickly by reducing the timing interval and sending the metrics body to local logging as well as to the caps service. --- indra/newview/llappviewer.cpp | 21 +- indra/newview/lltexturefetch.cpp | 67 ++++--- indra/newview/llviewerassetstats.cpp | 248 +++++++++++++++++++++++- indra/newview/llviewerassetstats.h | 60 ++++-- indra/newview/tests/llviewerassetstats_test.cpp | 134 ++++++++++--- 5 files changed, 443 insertions(+), 87 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2e056238e4..e696e1af84 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -336,10 +336,9 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ; //---------------------------------------------------------------------------- // Metrics logging control constants //---------------------------------------------------------------------------- -static const F32 METRICS_INTERVAL_MIN = 300.0; -static const F32 METRICS_INTERVAL_MAX = 3600.0; static const F32 METRICS_INTERVAL_DEFAULT = 600.0; - +static const F32 METRICS_INTERVAL_QA = 30.0; +static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT; void idle_afk_check() { @@ -664,8 +663,15 @@ bool LLAppViewer::init() // Called before threads are created. LLCurl::initClass(); LLMachineID::init(); - - LLViewerAssetStatsFF::init(); + + { + // Viewer metrics initialization + if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode")) + { + app_metrics_interval = METRICS_INTERVAL_QA; + } + LLViewerAssetStatsFF::init(); + } initThreads(); writeSystemInfo(); @@ -3701,7 +3707,7 @@ void LLAppViewer::idle() static LLTimer report_interval; // *TODO: Add configuration controls for this - if (report_interval.getElapsedTimeF32() >= METRICS_INTERVAL_DEFAULT) + if (report_interval.getElapsedTimeF32() >= app_metrics_interval) { metricsIdle(! gDisconnected); report_interval.reset(); @@ -4595,7 +4601,6 @@ void LLAppViewer::metricsIdle(bool enable_reporting) if (regionp) { caps_url = regionp->getCapability("ViewerMetrics"); - caps_url = "http://localhost:80/putz/"; } if (enable_reporting && regionp && ! caps_url.empty()) @@ -4608,9 +4613,9 @@ void LLAppViewer::metricsIdle(bool enable_reporting) LLSD * envelope = new LLSD(LLSD::emptyMap()); { + (*envelope) = gViewerAssetStatsMain->asLLSD(); (*envelope)["session_id"] = gAgentSessionID; (*envelope)["agent_id"] = gAgentID; - (*envelope)["regions"] = gViewerAssetStatsMain->asLLSD(); } if (LLAppViewer::sTextureFetch) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index df99818ee9..d303d425c8 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2764,68 +2764,77 @@ TFReqSendMetrics::doWork(LLTextureFetchWorker * fetch_worker) class lcl_responder : public LLCurl::Responder { public: - lcl_responder(volatile bool & post_failed, - volatile bool & post_succeeded) + lcl_responder(volatile bool & reporting_break, + volatile bool & reporting_started) : LLHTTPClient::Responder(), - mPostFailedStatus(post_failed), - mPostSucceededStatus(post_succeeded) + mReportingBreak(reporting_break), + mReportingStarted(reporting_started) {} // virtual void error(U32 status_num, const std::string & reason) { - mPostFailedStatus = true; + mReportingBreak = true; } // virtual void result(const LLSD & content) { - mPostSucceededStatus = true; + mReportingBreak = false; + mReportingStarted = true; } private: - volatile bool & mPostFailedStatus; - volatile bool & mPostSucceededStatus; + volatile bool & mReportingBreak; + volatile bool & mReportingStarted; }; if (! gViewerAssetStatsThread1) return true; - if (! mCapsURL.empty()) - { - static volatile bool not_initial_report(false); - static S32 report_sequence(0); + static volatile bool reporting_started(false); + static S32 report_sequence(0); - // We've already taken over ownership of the LLSD at this point - // and can do normal LLSD sharing operations at this point. But - // still being careful, regardless. - LLSD & envelope = *mReportMain; - { - envelope["sequence"] = report_sequence; - envelope["regions_alt"] = gViewerAssetStatsThread1->asLLSD(); - envelope["initial"] = ! not_initial_report; // Initial data from viewer - envelope["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report + // We've already taken over ownership of the LLSD at this point + // and can do normal LLSD sharing operations at this point. But + // still being careful, regardless. + LLSD & main_stats = *mReportMain; - // *FIXME: Need to merge the two metrics streams here.... - } + LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD(); // 'duration' & 'regions' from here + thread1_stats["message"] = "ViewerAssetMetrics"; + thread1_stats["sequence"] = report_sequence; + thread1_stats["initial"] = ! reporting_started; // Initial data from viewer + thread1_stats["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report + + // Update sequence number + if (S32_MAX == ++report_sequence) + report_sequence = 0; + + // Merge the two LLSDs into a single report + LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats); - // Update sequence number and other metadata for next attempt. - if (S32_MAX == ++report_sequence) - report_sequence = 0; - LLTextureFetch::svMetricsDataBreak = false; + // *TODO: Consider putting a report size limiter here. + if (! mCapsURL.empty()) + { LLCurlRequest::headers_t headers; fetch_worker->getFetcher().getCurlRequest().post(mCapsURL, headers, - envelope, + thread1_stats, new lcl_responder(LLTextureFetch::svMetricsDataBreak, - not_initial_report)); + reporting_started)); } else { LLTextureFetch::svMetricsDataBreak = true; } + // In QA mode, Metrics submode, log the result for ease of testing + if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode")) + { + LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL; + } + gViewerAssetStatsThread1->reset(); return true; diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index 09c0364f09..c0287863f6 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -113,6 +113,16 @@ LLViewerAssetStats::PerRegionStats::reset() mRequests[i].mDequeued.reset(); mRequests[i].mResponse.reset(); } + + mTotalTime = 0; + mStartTimestamp = LLViewerAssetStatsFF::get_timestamp(); +} + +void +LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now) +{ + mTotalTime += (now - mStartTimestamp); + mStartTimestamp = now; } @@ -144,6 +154,9 @@ LLViewerAssetStats::reset() // And add reference to map mRegionStats[mRegionID] = mCurRegionStats; + + // Start timestamp consistent with per-region collector + mResetTimestamp = mCurRegionStats->mStartTimestamp; } @@ -155,7 +168,12 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id) // Already active, ignore. return; } - + + // Get duration for current set + const duration_t now = LLViewerAssetStatsFF::get_timestamp(); + mCurRegionStats->accumulateTime(now); + + // Prepare new set PerRegionContainer::iterator new_stats = mRegionStats.find(region_id); if (mRegionStats.end() == new_stats) { @@ -167,6 +185,7 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id) { mCurRegionStats = new_stats->second; } + mCurRegionStats->mStartTimestamp = now; mRegionID = region_id; } @@ -195,8 +214,8 @@ LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_htt mCurRegionStats->mRequests[int(eac)].mResponse.record(duration); } -const LLSD -LLViewerAssetStats::asLLSD() const +LLSD +LLViewerAssetStats::asLLSD() { // Top-level tags static const LLSD::String tags[EVACCount] = @@ -211,17 +230,18 @@ LLViewerAssetStats::asLLSD() const LLSD::String("get_other") }; - // Sub-tags + // Sub-tags. If you add or delete from this list, mergeLLSD() must be updated. static const LLSD::String enq_tag("enqueued"); static const LLSD::String deq_tag("dequeued"); static const LLSD::String rcnt_tag("resp_count"); static const LLSD::String rmin_tag("resp_min"); static const LLSD::String rmax_tag("resp_max"); static const LLSD::String rmean_tag("resp_mean"); - - LLSD ret = LLSD::emptyMap(); - for (PerRegionContainer::const_iterator it = mRegionStats.begin(); + const duration_t now = LLViewerAssetStatsFF::get_timestamp(); + LLSD regions = LLSD::emptyMap(); + + for (PerRegionContainer::iterator it = mRegionStats.begin(); mRegionStats.end() != it; ++it) { @@ -231,7 +251,8 @@ LLViewerAssetStats::asLLSD() const continue; } - const PerRegionStats & stats = *it->second; + PerRegionStats & stats = *it->second; + stats.accumulateTime(now); LLSD reg_stat = LLSD::emptyMap(); @@ -247,12 +268,185 @@ LLViewerAssetStats::asLLSD() const slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean())); } - ret[it->first.asString()] = reg_stat; + reg_stat["duration"] = LLSD::Integer(stats.mTotalTime / 1000000); + + regions[it->first.asString()] = reg_stat; } + LLSD ret = LLSD::emptyMap(); + ret["regions"] = regions; + ret["duration"] = LLSD::Integer((now - mResetTimestamp) / 1000000); + return ret; } +/* static */ void +LLViewerAssetStats::mergeLLSD(const LLSD & src, LLSD & dst) +{ + // Merge operator definitions + static const int MOP_ADD_INT(0); + static const int MOP_MIN_REAL(1); + static const int MOP_MAX_REAL(2); + static const int MOP_MEAN_REAL(3); // Requires a 'mMergeOpArg' to weight the input terms + + static const LLSD::String regions_key("regions"); + static const LLSD::String root_key_list[] = + { + "duration", + regions_key + }; + + static const struct + { + LLSD::String mName; + int mMergeOp; + LLSD::String mMergeOpArg; + } + key_list[] = + { + // Order is important below. We modify the data in-place and + // so operations like MOP_MEAN_REAL which need the "resp_count" + // value for weighting must be performed before "resp_count" + // is modified or the weight will be wrong. Key list is + // defined in asLLSD() and must track it. + + { "resp_mean", MOP_MEAN_REAL, "resp_count" }, + { "enqueued", MOP_ADD_INT, "" }, + { "dequeued", MOP_ADD_INT, "" }, + { "resp_count", MOP_ADD_INT, "" }, + { "resp_min", MOP_MIN_REAL, "" }, + { "resp_max", MOP_MAX_REAL, "" } + }; + + // First normalized the root keys but remember if we need to do full merge + const bool needs_deep_merge(src.has(regions_key) && dst.has(regions_key)); + + for (int root_index(0); root_index < LL_ARRAY_SIZE(root_key_list); ++root_index) + { + const LLSD::String & key_name(root_key_list[root_index]); + + if ((! src.has(key_name)) || dst.has(key_name)) + continue; + + // key present in source, not in dst here + dst[key_name] = src[key_name]; + } + + if (! needs_deep_merge) + return; + + // Okay, had both src and dst 'regions' section, do the deep merge + + const LLSD & root_src(src[regions_key]); + LLSD & root_dst(dst[regions_key]); + + const LLSD::map_const_iterator it_end(root_src.endMap()); + for (LLSD::map_const_iterator it(root_src.beginMap()); it_end != it; ++it) + { + if (! root_dst.has(it->first)) + { + // src[] without matching dst[] + root_dst[it->first] = it->second; + } + else + { + // src[] with matching dst[] + // We have matching source and destination regions. + // Now iterate over each asset bin in the region status. Could iterate over + // an explicit list but this will do as well. + LLSD & reg_dst(root_dst[it->first]); + const LLSD & reg_src(root_src[it->first]); + + const LLSD::map_const_iterator it_src_bin_end(reg_src.endMap()); + for (LLSD::map_const_iterator it_src_bin(reg_src.beginMap()); it_src_bin_end != it_src_bin; ++it_src_bin) + { + static const LLSD::String no_touch_1("duration"); + + if (no_touch_1 == it_src_bin->first) + { + continue; + } + else if (! reg_dst.has(it_src_bin->first)) + { + // src[][] without matching dst[][] + reg_dst[it_src_bin->first] = it_src_bin->second; + } + else + { + // src[][] with matching dst[][] + // Matching stats bin in both source and destination regions. + // Iterate over those bin keys we know how to merge, leave the remainder untouched. + LLSD & bin_dst(reg_dst[it_src_bin->first]); + const LLSD & bin_src(reg_src[it_src_bin->first]); + + for (int key_index(0); key_index < LL_ARRAY_SIZE(key_list); ++key_index) + { + const LLSD::String & key_name(key_list[key_index].mName); + + if (! bin_src.has(key_name)) + { + // Missing src[][][] + continue; + } + + const LLSD & src_value(bin_src[key_name]); + + if (! bin_dst.has(key_name)) + { + // src[][][] without matching dst[][][] + bin_dst[key_name] = src_value; + } + else + { + // src[][][] with matching dst[][][] + LLSD & dst_value(bin_dst[key_name]); + + switch (key_list[key_index].mMergeOp) + { + case MOP_ADD_INT: + // Simple counts, just add + dst_value = dst_value.asInteger() + src_value.asInteger(); + + break; + + case MOP_MIN_REAL: + // Minimum + dst_value = llmin(dst_value.asReal(), src_value.asReal()); + break; + + case MOP_MAX_REAL: + // Maximum + dst_value = llmax(dst_value.asReal(), src_value.asReal()); + break; + + case MOP_MEAN_REAL: + { + // Mean + const LLSD::String & weight_key(key_list[key_index].mMergeOpArg); + F64 src_weight(bin_src[weight_key].asReal()); + F64 dst_weight(bin_dst[weight_key].asReal()); + F64 tot_weight(src_weight + dst_weight); + if (tot_weight >= F64(0.5)) + { + dst_value = (((dst_value.asReal() * dst_weight) + + (src_value.asReal() * src_weight)) + / tot_weight); + } + } + break; + + default: + break; + } + } + } + } + } + } + } +} + + // ------------------------------------------------------ // Global free-function definitions (LLViewerAssetStatsFF namespace) // ------------------------------------------------------ @@ -377,7 +571,43 @@ cleanup() delete gViewerAssetStatsThread1; gViewerAssetStatsThread1 = 0; } + + +void +merge_stats(const LLSD & src, LLSD & dst) +{ + static const LLSD::String regions_key("regions"); + static const LLSD::String dur_key("duration"); + + // Trivial cases first + if (! src.isMap()) + { + return; + } + + if (! dst.isMap()) + { + dst = src; + return; + } + // Okay, both src and dst are maps at this point. + // Collector class know how to merge it's part + LLViewerAssetStats::mergeLLSD(src, dst); + + // Now merge non-collector bits manually. + const LLSD::map_const_iterator it_end(src.endMap()); + for (LLSD::map_const_iterator it(src.beginMap()); it_end != it; ++it) + { + if (regions_key == it->first || dur_key == it->first) + continue; + + if (dst.has(it->first)) + continue; + + dst[it->first] = it->second; + } +} } // namespace LLViewerAssetStatsFF diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index efd0897bb8..65ecdca4a0 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -83,10 +83,10 @@ class LLViewerAssetStats public: enum EViewerAssetCategories { - EVACTextureTempHTTPGet, //< Texture GETs - EVACTextureTempUDPGet, //< Texture GETs - EVACTextureNonTempHTTPGet, //< Texture GETs - EVACTextureNonTempUDPGet, //< Texture GETs + EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP + EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP + EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP + EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP EVACWearableUDPGet, //< Wearable GETs EVACSoundUDPGet, //< Sound GETs EVACGestureUDPGet, //< Gesture GETs @@ -103,7 +103,11 @@ public: typedef U64 duration_t; /** - * Collected data for a single region visited by the avatar. + * @brief Collected data for a single region visited by the avatar. + * + * Fairly simple, for each asset bin enumerated above a count + * of enqueue and dequeue operations and simple stats on response + * times for completed requests. */ class PerRegionStats : public LLRefCount { @@ -118,8 +122,15 @@ public: void reset(); + // Apply current running time to total and reset start point. + // Return current timestamp as a convenience. + void accumulateTime(duration_t now); + public: LLUUID mRegionID; + duration_t mTotalTime; + duration_t mStartTimestamp; + struct { LLSimpleStatCounter mEnqueued; @@ -142,13 +153,17 @@ public: // collection calls. void setRegionID(const LLUUID & region_id); - // Non-Cached GET Requests + // Asset GET Requests void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp); void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp); void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration); - // Retrieve current metrics for all visited regions. - const LLSD asLLSD() const; + // Retrieve current metrics for all visited regions (NULL region UUID excluded) + LLSD asLLSD(); + + // Merge two LLSD's structured as per asLLSD(). If inputs are not + // correctly formed, result is undefined (little defensive action). + static void mergeLLSD(const LLSD & src, LLSD & dst); protected: typedef std::map > PerRegionContainer; @@ -165,6 +180,9 @@ protected: // Metrics data for all regions during one collection cycle PerRegionContainer mRegionStats; + + // Time of last reset + duration_t mResetTimestamp; }; @@ -188,6 +206,17 @@ extern LLViewerAssetStats * gViewerAssetStatsThread1; namespace LLViewerAssetStatsFF { +/** + * @brief Allocation and deallocation of globals. + * + * init() should be called before threads are started that will access it though + * you'll likely get away with calling it afterwards. cleanup() should only be + * called after threads are shutdown to prevent races on the global pointers. + */ +void init(); + +void cleanup(); + /** * We have many timers, clocks etc. in the runtime. This is the * canonical timestamp for these metrics which is compatible with @@ -224,15 +253,16 @@ void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool i LLViewerAssetStats::duration_t duration); /** - * @brief Allocation and deallocation of globals. + * @brief Merge two LLSD reports from different collector instances * - * init() should be called before threads are started that will access it though - * you'll likely get away with calling it afterwards. cleanup() should only be - * called after threads are shutdown to prevent races on the global pointers. + * Use this to merge the LLSD's from two threads. For top-level, + * non-region data the destination (dst) is considered authoritative + * if the key is present in both source and destination. For + * regions, a numerical merge is performed when data are present in + * both source and destination and the 'right thing' is done for + * counts, minimums, maximums and averages. */ -void init(); - -void cleanup(); +void merge_stats(const LLSD & src, LLSD & dst); } // namespace LLViewerAssetStatsFF diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index c3c38ef925..e8cde5fc5d 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -39,9 +39,11 @@ #include "lltut.h" #include "../llviewerassetstats.h" #include "lluuid.h" +#include "llsdutil.h" static const char * all_keys[] = { + "duration", "get_other", "get_texture_temp_http", "get_texture_temp_udp", @@ -77,11 +79,13 @@ static const char * sub_keys[] = static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8"); static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a"); +#if 0 static bool is_empty_map(const LLSD & sd) { return sd.isMap() && 0 == sd.size(); } +#endif static bool is_single_key_map(const LLSD & sd, const std::string & key) @@ -95,6 +99,12 @@ is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2); } +static bool +is_no_stats_map(const LLSD & sd) +{ + return is_double_key_map(sd, "duration", "regions"); +} + namespace tut { struct tst_viewerassetstats_index @@ -131,14 +141,15 @@ namespace tut // Default (NULL) region ID doesn't produce LLSD results so should // get an empty map back from output - ensure("Null LLSD initially", is_empty_map(sd_full)); + ensure("Stat-less LLSD initially", is_no_stats_map(sd_full)); // Once the region is set, we will get a response even with no data collection it->setRegionID(region1); sd_full = it->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd_full, region1.asString())); - - LLSD sd = sd_full[region1.asString()]; + ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1.asString())); + + LLSD sd = sd_full["regions"][region1.asString()]; delete it; @@ -167,7 +178,8 @@ namespace tut it->setRegionID(region1); LLSD sd = it->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); sd = sd[region1.asString()]; delete it; @@ -191,8 +203,9 @@ namespace tut LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); LLSD sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); - sd = sd[region1.asString()]; + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); + sd = sd["regions"][region1.asString()]; // Check a few points on the tree for content ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -204,7 +217,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()[region1.asString()]; + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -228,10 +241,11 @@ namespace tut LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); LLSD sd = gViewerAssetStatsThread1->asLLSD(); - ensure("Other collector is empty", is_empty_map(sd)); + ensure("Other collector is empty", is_no_stats_map(sd)); sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); - sd = sd[region1.asString()]; + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); + sd = sd["regions"][region1.asString()]; // Check a few points on the tree for content ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -243,7 +257,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()[region1.asString()]; + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -277,9 +291,12 @@ namespace tut LLSD sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct double-key LLSD map", is_double_key_map(sd, region1.asString(), region2.asString())); - LLSD sd1 = sd[region1.asString()]; - LLSD sd2 = sd[region2.asString()]; + // std::cout << sd << std::endl; + + ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); + ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString())); + LLSD sd1 = sd["regions"][region1.asString()]; + LLSD sd2 = sd["regions"][region2.asString()]; // Check a few points on the tree for content ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -297,8 +314,9 @@ namespace tut // Reset leaves current region in place gViewerAssetStatsMain->reset(); sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd, region2.asString())); - sd2 = sd[region2.asString()]; + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString())); + sd2 = sd["regions"][region2.asString()]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -345,9 +363,10 @@ namespace tut LLSD sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct double-key LLSD map", is_double_key_map(sd, region1.asString(), region2.asString())); - LLSD sd1 = sd[region1.asString()]; - LLSD sd2 = sd[region2.asString()]; + ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); + ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString())); + LLSD sd1 = sd["regions"][region1.asString()]; + LLSD sd2 = sd["regions"][region2.asString()]; // Check a few points on the tree for content ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -365,8 +384,9 @@ namespace tut // Reset leaves current region in place gViewerAssetStatsMain->reset(); sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd, region2.asString())); - sd2 = sd[region2.asString()]; + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString())); + sd2 = sd["regions"][region2.asString()]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -407,10 +427,11 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true); LLSD sd = gViewerAssetStatsThread1->asLLSD(); - ensure("Other collector is empty", is_empty_map(sd)); + ensure("Other collector is empty", is_no_stats_map(sd)); sd = gViewerAssetStatsMain->asLLSD(); - ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); - sd = sd[region1.asString()]; + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); + sd = sd["regions"][region1.asString()]; // Check a few points on the tree for content ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger())); @@ -425,7 +446,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()[region1.asString()]; + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -436,4 +457,65 @@ namespace tut ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); } + // Check that the LLSD merger knows what it's doing (basic test) + template<> template<> + void tst_viewerassetstats_index_object_t::test<9>() + { + LLSD::String reg1_name = region1.asString(); + LLSD::String reg2_name = region2.asString(); + + LLSD reg1_stats = LLSD::emptyMap(); + LLSD reg2_stats = LLSD::emptyMap(); + + LLSD & tmp_other1 = reg1_stats["get_other"]; + tmp_other1["enqueued"] = 4; + tmp_other1["dequeued"] = 4; + tmp_other1["resp_count"] = 8; + tmp_other1["resp_max"] = F64(23.2892); + tmp_other1["resp_min"] = F64(0.2829); + tmp_other1["resp_mean"] = F64(2.298928); + + LLSD & tmp_other2 = reg2_stats["get_other"]; + tmp_other2["enqueued"] = 8; + tmp_other2["dequeued"] = 7; + tmp_other2["resp_count"] = 3; + tmp_other2["resp_max"] = F64(6.5); + tmp_other2["resp_min"] = F64(0.01); + tmp_other2["resp_mean"] = F64(4.1); + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg2_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeLLSD(src, dst); + + ensure("region 1 in merged stats", llsd_equals(reg1_stats, dst["regions"][reg1_name])); + ensure("region 2 still in merged stats", llsd_equals(reg2_stats, dst["regions"][reg2_name])); + } + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeLLSD(src, dst); + + ensure("src not ruined", llsd_equals(reg1_stats, src["regions"][reg1_name])); + ensure_equals("added enqueued counts", dst["regions"][reg1_name]["get_other"]["enqueued"].asInteger(), 12); + ensure_equals("added dequeued counts", dst["regions"][reg1_name]["get_other"]["dequeued"].asInteger(), 11); + ensure_equals("added response counts", dst["regions"][reg1_name]["get_other"]["resp_count"].asInteger(), 11); + ensure_approximately_equals("min'd minimum response times", dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), 0.01, 20); + ensure_approximately_equals("max'd maximum response times", dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), 23.2892, 20); + ensure_approximately_equals("weighted mean of means", dst["regions"][reg1_name]["get_other"]["resp_mean"].asReal(), 2.7901295, 20); + } + } } -- cgit v1.3 From 9ec3334184c71879c2f8bd0f27095b71c4302559 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Tue, 23 Nov 2010 13:31:22 -0500 Subject: ESC-154 ESC-156 Data collection and control for viewer metrics Detect QAMode (and new QAModeMetricsSubmode) settings which enable logging of metrics report locally and a faster cycle time to reduce test waiting. Do this only in the main thread and propagate the result via collector constructors (will likely move that out and put it in llappviewer/lltexturefetch which is more correct scope). Managed to deadlock myself with a recursive mutex (sheesh). --- indra/newview/llappviewer.cpp | 11 +++++++++-- indra/newview/lltexturefetch.cpp | 7 +++---- indra/newview/llviewerassetstats.cpp | 9 +++++---- indra/newview/llviewerassetstats.h | 14 ++++++++++---- indra/newview/tests/llviewerassetstats_test.cpp | 18 +++++++++--------- 5 files changed, 36 insertions(+), 23 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e696e1af84..587d887146 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -666,11 +666,18 @@ bool LLAppViewer::init() { // Viewer metrics initialization - if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode")) + static LLCachedControl metrics_submode(gSavedSettings, + "QAModeMetricsSubmode", + FALSE, + "Enables metrics submode when QAMode is also enabled"); + + bool qa_mode(false); + if (gSavedSettings.getBOOL("QAMode") && metrics_submode) { app_metrics_interval = METRICS_INTERVAL_QA; + qa_mode = true; } - LLViewerAssetStatsFF::init(); + LLViewerAssetStatsFF::init(qa_mode); } initThreads(); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index e574a35479..8e43084adb 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2680,8 +2680,9 @@ void LLTextureFetch::cmdEnqueue(TFRequest * req) { lockQueue(); mCommands.push_back(req); - wake(); unlockQueue(); + + wake(); } TFRequest * LLTextureFetch::cmdDequeue() @@ -2706,7 +2707,6 @@ void LLTextureFetch::cmdDoWork() return; // debug: don't do any work } - lockQueue(); TFRequest * req = cmdDequeue(); if (req) { @@ -2714,7 +2714,6 @@ void LLTextureFetch::cmdDoWork() req->doWork(this); delete req; } - unlockQueue(); } @@ -2834,7 +2833,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) } // In QA mode, Metrics submode, log the result for ease of testing - if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode")) + if (gViewerAssetStatsThread1->isQAMode()) { LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL; } diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index c3e58cdd56..a63c1bf66d 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -129,7 +129,8 @@ LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now) // ------------------------------------------------------ // LLViewerAssetStats class definition // ------------------------------------------------------ -LLViewerAssetStats::LLViewerAssetStats() +LLViewerAssetStats::LLViewerAssetStats(bool qa_mode) + : mQAMode(qa_mode) { reset(); } @@ -539,15 +540,15 @@ record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_tem void -init() +init(bool qa_mode) { if (! gViewerAssetStatsMain) { - gViewerAssetStatsMain = new LLViewerAssetStats; + gViewerAssetStatsMain = new LLViewerAssetStats(qa_mode); } if (! gViewerAssetStatsThread1) { - gViewerAssetStatsThread1 = new LLViewerAssetStats; + gViewerAssetStatsThread1 = new LLViewerAssetStats(qa_mode); } } diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index cb63b9c511..1668a1bc9d 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -140,7 +140,7 @@ public: }; public: - LLViewerAssetStats(); + LLViewerAssetStats(bool qa_mode); // Default destructor is correct. LLViewerAssetStats & operator=(const LLViewerAssetStats &); // Not defined @@ -196,6 +196,10 @@ public: // level. The "regions" information must be correctly formed or the // final result is undefined (little defensive action). static void mergeRegionsLLSD(const LLSD & src, LLSD & dst); + + // QA mode is established during initialization so we don't + // touch LLSD at runtime. + bool isQAMode() const { return mQAMode; } protected: typedef std::map > PerRegionContainer; @@ -215,6 +219,9 @@ protected: // Time of last reset duration_t mResetTimestamp; + + // QA Mode + const bool mQAMode; }; @@ -245,7 +252,7 @@ namespace LLViewerAssetStatsFF * you'll likely get away with calling it afterwards. cleanup() should only be * called after threads are shutdown to prevent races on the global pointers. */ -void init(); +void init(bool qa_mode); void cleanup(); @@ -298,5 +305,4 @@ void merge_stats(const LLSD & src, LLSD & dst); } // namespace LLViewerAssetStatsFF - -#endif // LL_LLVIEWERASSETSTATUS_H +#endif // LL_LLVIEWERASSETSTATUS_H diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index a44712e8ad..5a178fc585 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -133,7 +133,7 @@ namespace tut { ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); - LLViewerAssetStats * it = new LLViewerAssetStats(); + LLViewerAssetStats * it = new LLViewerAssetStats(false); ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain)); @@ -174,7 +174,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<3>() { - LLViewerAssetStats * it = new LLViewerAssetStats(); + LLViewerAssetStats * it = new LLViewerAssetStats(false); it->setRegionID(region1); LLSD sd = it->asLLSD(); @@ -193,7 +193,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<4>() { - gViewerAssetStatsMain = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(false); LLViewerAssetStatsFF::set_region_main(region1); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -230,8 +230,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<5>() { - gViewerAssetStatsThread1 = new LLViewerAssetStats(); - gViewerAssetStatsMain = new LLViewerAssetStats(); + gViewerAssetStatsThread1 = new LLViewerAssetStats(false); + gViewerAssetStatsMain = new LLViewerAssetStats(false); LLViewerAssetStatsFF::set_region_main(region1); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -272,7 +272,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<6>() { - gViewerAssetStatsMain = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(false); LLViewerAssetStatsFF::set_region_main(region1); @@ -329,7 +329,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<7>() { - gViewerAssetStatsMain = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(false); LLViewerAssetStatsFF::set_region_main(region1); @@ -399,8 +399,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<8>() { - gViewerAssetStatsThread1 = new LLViewerAssetStats(); - gViewerAssetStatsMain = new LLViewerAssetStats(); + gViewerAssetStatsThread1 = new LLViewerAssetStats(false); + gViewerAssetStatsMain = new LLViewerAssetStats(false); LLViewerAssetStatsFF::set_region_main(region1); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); -- cgit v1.3 From 3962b155b4939f831dfd82701d46c4f15aa9f7ac Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Tue, 23 Nov 2010 12:29:15 -0800 Subject: ESC-154 ESC-156 Integrating metrics collector into viewer. After discussions, renamed 'QAModeMetricsSubmetrics' to 'QAModeMetrics' and confirmed that LLCachedControl<> is the way to go. Moved the resulting flag out of LLViewerAssetStats (where it didn't belong) and it lives in both LLAppViewer and LLTextureFetch where it does belong. --- indra/newview/llappviewer.cpp | 17 +++++++----- indra/newview/lltexturefetch.cpp | 7 ++--- indra/newview/lltexturefetch.h | 36 ++++++++++++++++++++++--- indra/newview/llviewerassetstats.cpp | 9 +++---- indra/newview/llviewerassetstats.h | 11 ++------ indra/newview/tests/llviewerassetstats_test.cpp | 18 ++++++------- 6 files changed, 62 insertions(+), 36 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 587d887146..07f4e71ebf 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -339,6 +339,7 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ; static const F32 METRICS_INTERVAL_DEFAULT = 600.0; static const F32 METRICS_INTERVAL_QA = 30.0; static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT; +static bool app_metrics_qa_mode = false; void idle_afk_check() { @@ -667,17 +668,16 @@ bool LLAppViewer::init() { // Viewer metrics initialization static LLCachedControl metrics_submode(gSavedSettings, - "QAModeMetricsSubmode", + "QAModeMetrics", FALSE, - "Enables metrics submode when QAMode is also enabled"); + "Enables QA features (logging, faster cycling) for metrics collector"); - bool qa_mode(false); - if (gSavedSettings.getBOOL("QAMode") && metrics_submode) + if (metrics_submode) { + app_metrics_qa_mode = true; app_metrics_interval = METRICS_INTERVAL_QA; - qa_mode = true; } - LLViewerAssetStatsFF::init(qa_mode); + LLViewerAssetStatsFF::init(); } initThreads(); @@ -1760,7 +1760,10 @@ bool LLAppViewer::initThreads() // Image decoding LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); - LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true); + LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), + sImageDecodeThread, + enable_threads && true, + app_metrics_qa_mode); LLImage::initClass(); if (LLFastTimer::sLog || LLFastTimer::sMetricLog) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 8e43084adb..2e05a67791 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1774,7 +1774,7 @@ bool LLTextureFetchWorker::writeToCacheComplete() ////////////////////////////////////////////////////////////////////////////// // public -LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded) +LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode) : LLWorkerThread("TextureFetch", threaded), mDebugCount(0), mDebugPause(FALSE), @@ -1786,7 +1786,8 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), mHTTPTextureBits(0), - mCurlGetRequest(NULL) + mCurlGetRequest(NULL), + mQAMode(qa_mode) { mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); @@ -2833,7 +2834,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) } // In QA mode, Metrics submode, log the result for ease of testing - if (gViewerAssetStatsThread1->isQAMode()) + if (fetcher->isQAMode()) { LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL; } diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 88b7e4a16b..d46d2da7bc 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -49,7 +49,7 @@ class LLTextureFetch : public LLWorkerThread friend class HTTPGetResponder; public: - LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded); + LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode); ~LLTextureFetch(); /*virtual*/ S32 update(U32 max_time_ms); @@ -90,8 +90,10 @@ public: void commandSendMetrics(const std::string & caps_url, LLSD * report_main); void commandDataBreak(); - LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; } - + LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; } + + bool isQAMode() const { return mQAMode; } + protected: void addToNetworkQueue(LLTextureFetchWorker* worker); void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel); @@ -109,8 +111,33 @@ private: /*virtual*/ void threadedUpdate(void); // Metrics command helpers + /** + * Enqueues a command request at the end of the command queue + * and wakes up the thread as needed. + * + * Takes ownership of the TFRequest object. + * + * Method locks the command queue. + */ void cmdEnqueue(TFRequest *); + + /** + * Returns the first TFRequest object in the command queue or + * NULL if none is present. + * + * Caller acquires ownership of the object and must dispose of it. + * + * Method locks the command queue. + */ TFRequest * cmdDequeue(); + + /** + * Processes the first command in the queue disposing of the + * request on completion. Successive calls are needed to perform + * additional commands. + * + * Method locks the command queue. + */ void cmdDoWork(); public: @@ -151,6 +178,9 @@ private: typedef std::vector command_queue_t; command_queue_t mCommands; + // If true, modifies some behaviors that help with QA tasks. + const bool mQAMode; + public: // A probabilistically-correct indicator that the current // attempt to log metrics follows a break in the metrics stream diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index a63c1bf66d..3d7f9f932f 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -129,8 +129,7 @@ LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now) // ------------------------------------------------------ // LLViewerAssetStats class definition // ------------------------------------------------------ -LLViewerAssetStats::LLViewerAssetStats(bool qa_mode) - : mQAMode(qa_mode) +LLViewerAssetStats::LLViewerAssetStats() { reset(); } @@ -540,15 +539,15 @@ record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_tem void -init(bool qa_mode) +init() { if (! gViewerAssetStatsMain) { - gViewerAssetStatsMain = new LLViewerAssetStats(qa_mode); + gViewerAssetStatsMain = new LLViewerAssetStats(); } if (! gViewerAssetStatsThread1) { - gViewerAssetStatsThread1 = new LLViewerAssetStats(qa_mode); + gViewerAssetStatsThread1 = new LLViewerAssetStats(); } } diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index 1668a1bc9d..b0fb17ae17 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -140,7 +140,7 @@ public: }; public: - LLViewerAssetStats(bool qa_mode); + LLViewerAssetStats(); // Default destructor is correct. LLViewerAssetStats & operator=(const LLViewerAssetStats &); // Not defined @@ -197,10 +197,6 @@ public: // final result is undefined (little defensive action). static void mergeRegionsLLSD(const LLSD & src, LLSD & dst); - // QA mode is established during initialization so we don't - // touch LLSD at runtime. - bool isQAMode() const { return mQAMode; } - protected: typedef std::map > PerRegionContainer; @@ -219,9 +215,6 @@ protected: // Time of last reset duration_t mResetTimestamp; - - // QA Mode - const bool mQAMode; }; @@ -252,7 +245,7 @@ namespace LLViewerAssetStatsFF * you'll likely get away with calling it afterwards. cleanup() should only be * called after threads are shutdown to prevent races on the global pointers. */ -void init(bool qa_mode); +void init(); void cleanup(); diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 5a178fc585..a44712e8ad 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -133,7 +133,7 @@ namespace tut { ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); - LLViewerAssetStats * it = new LLViewerAssetStats(false); + LLViewerAssetStats * it = new LLViewerAssetStats(); ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain)); @@ -174,7 +174,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<3>() { - LLViewerAssetStats * it = new LLViewerAssetStats(false); + LLViewerAssetStats * it = new LLViewerAssetStats(); it->setRegionID(region1); LLSD sd = it->asLLSD(); @@ -193,7 +193,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<4>() { - gViewerAssetStatsMain = new LLViewerAssetStats(false); + gViewerAssetStatsMain = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region_main(region1); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -230,8 +230,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<5>() { - gViewerAssetStatsThread1 = new LLViewerAssetStats(false); - gViewerAssetStatsMain = new LLViewerAssetStats(false); + gViewerAssetStatsThread1 = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region_main(region1); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -272,7 +272,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<6>() { - gViewerAssetStatsMain = new LLViewerAssetStats(false); + gViewerAssetStatsMain = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region_main(region1); @@ -329,7 +329,7 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<7>() { - gViewerAssetStatsMain = new LLViewerAssetStats(false); + gViewerAssetStatsMain = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region_main(region1); @@ -399,8 +399,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<8>() { - gViewerAssetStatsThread1 = new LLViewerAssetStats(false); - gViewerAssetStatsMain = new LLViewerAssetStats(false); + gViewerAssetStatsThread1 = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region_main(region1); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); -- cgit v1.3 From 6abc60be577bd29c2428d85143c8f583eab54723 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Tue, 23 Nov 2010 17:28:21 -0500 Subject: ESC-154 ESC-156 Viewer metrics Get the metrics message generation working in QAModeMetrics mode. Sample interval and data aren't correct yet but getting there. --- indra/newview/llappviewer.cpp | 50 +++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 07f4e71ebf..86fba90ff7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -667,9 +667,9 @@ bool LLAppViewer::init() { // Viewer metrics initialization - static LLCachedControl metrics_submode(gSavedSettings, + static LLCachedControl metrics_submode(gSavedSettings, "QAModeMetrics", - FALSE, + false, "Enables QA features (logging, faster cycling) for metrics collector"); if (metrics_submode) @@ -4606,30 +4606,26 @@ void LLAppViewer::metricsIdle(bool enable_reporting) if (! gViewerAssetStatsMain) return; - std::string caps_url; - LLViewerRegion * regionp = gAgent.getRegion(); - if (regionp) + if (LLAppViewer::sTextureFetch) { - caps_url = regionp->getCapability("ViewerMetrics"); - } - - if (enable_reporting && regionp && ! caps_url.empty()) - { - // *NOTE: Pay attention here. LLSD's are not safe for thread sharing - // and their ownership is difficult to transfer across threads. We do - // it here by having only one reference (the new'd pointer) to the LLSD - // or any subtree of it. This pointer is then transfered to the other - // thread using correct thread logic. - - LLSD * envelope = new LLSD(LLSD::emptyMap()); + LLViewerRegion * regionp = gAgent.getRegion(); + + if (enable_reporting && regionp) { - (*envelope) = gViewerAssetStatsMain->asLLSD(); - (*envelope)["session_id"] = gAgentSessionID; - (*envelope)["agent_id"] = gAgentID; - } + std::string caps_url = regionp->getCapability("ViewerMetrics"); + + // *NOTE: Pay attention here. LLSD's are not safe for thread sharing + // and their ownership is difficult to transfer across threads. We do + // it here by having only one reference (the new'd pointer) to the LLSD + // or any subtree of it. This pointer is then transfered to the other + // thread using correct thread logic to do all data ordering. + LLSD * envelope = new LLSD(LLSD::emptyMap()); + { + (*envelope) = gViewerAssetStatsMain->asLLSD(); + (*envelope)["session_id"] = gAgentSessionID; + (*envelope)["agent_id"] = gAgentID; + } - if (LLAppViewer::sTextureFetch) - { // Send a report request into 'thread1' to get the rest of the data // and have it sent to the stats collector. LLSD ownership transfers // with this call. @@ -4638,15 +4634,9 @@ void LLAppViewer::metricsIdle(bool enable_reporting) } else { - // No 'thread1' so transfer doesn't happen and we need to clean up - delete envelope; - envelope = 0; + LLAppViewer::sTextureFetch->commandDataBreak(); } } - else - { - LLAppViewer::sTextureFetch->commandDataBreak(); - } // Reset even if we can't report. Rather than gather up a huge chunk of // data, we'll keep to our sampling interval and retain the data -- cgit v1.3 From 0fd80d09972657e6417193abf577084a3b3b85f1 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Wed, 24 Nov 2010 16:46:40 -0500 Subject: ESC-154 ESC-156 Metrics integration across threads Using unpause() method in derived class rather than wake() in furthest base class solved the stalling problem. I still think too many levels of the LLTextureFetch hierarchy are keeping thread state, however. The LLViewerRegion instance an agent enters doesn't necessarily have its region_id yet, that only comes after the handshake, if any. So add a few more metrics insertion points to propagate region into metrics. Finally, try to launch a final metrics report when a quit is initiated. --- indra/newview/llappviewer.cpp | 5 +++-- indra/newview/llappviewer.h | 2 +- indra/newview/lltexturefetch.cpp | 37 ++++++++++++++++++++----------------- indra/newview/lltexturefetch.h | 1 + indra/newview/llviewerregion.cpp | 8 ++++++++ 5 files changed, 33 insertions(+), 20 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 86fba90ff7..bf79523078 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2932,6 +2932,7 @@ void LLAppViewer::requestQuit() LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit")); send_stats(); + metricsSend(!gDisconnected); gLogoutTimer.reset(); mQuitRequested = true; @@ -3719,7 +3720,7 @@ void LLAppViewer::idle() // *TODO: Add configuration controls for this if (report_interval.getElapsedTimeF32() >= app_metrics_interval) { - metricsIdle(! gDisconnected); + metricsSend(! gDisconnected); report_interval.reset(); } } @@ -4601,7 +4602,7 @@ void LLAppViewer::metricsUpdateRegion(const LLUUID & region_id) * Attempts to start a multi-threaded metrics report to be sent back to * the grid for consumption. */ -void LLAppViewer::metricsIdle(bool enable_reporting) +void LLAppViewer::metricsSend(bool enable_reporting) { if (! gViewerAssetStatsMain) return; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 909f191ab1..27c104626a 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -170,7 +170,7 @@ public: // Metrics policy helper statics. static void metricsUpdateRegion(const LLUUID & region_id); - static void metricsIdle(bool enable_reporting); + static void metricsSend(bool enable_reporting); protected: virtual bool initWindow(); // Initialize the viewer's window. diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 2e05a67791..2be3ba3280 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2105,6 +2105,21 @@ bool LLTextureFetch::runCondition() ////////////////////////////////////////////////////////////////////////////// +// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs) +void LLTextureFetch::commonUpdate() +{ + // Run a cross-thread command, if any. + cmdDoWork(); + + // Update Curl on same thread as mCurlGetRequest was constructed + S32 processed = mCurlGetRequest->process(); + if (processed > 0) + { + lldebugs << "processed: " << processed << " messages." << llendl; + } +} + + // MAIN THREAD //virtual S32 LLTextureFetch::update(U32 max_time_ms) @@ -2130,12 +2145,7 @@ S32 LLTextureFetch::update(U32 max_time_ms) if (!mThreaded) { - // Update Curl on same thread as mCurlGetRequest was constructed - S32 processed = mCurlGetRequest->process(); - if (processed > 0) - { - lldebugs << "processed: " << processed << " messages." << llendl; - } + commonUpdate(); } return res; @@ -2190,15 +2200,7 @@ void LLTextureFetch::threadedUpdate() } process_timer.reset(); - // Run a cross-thread command, if any. - cmdDoWork(); - - // Update Curl on same thread as mCurlGetRequest was constructed - S32 processed = mCurlGetRequest->process(); - if (processed > 0) - { - lldebugs << "processed: " << processed << " messages." << llendl; - } + commonUpdate(); #if 0 const F32 INFO_TIME = 1.0f; @@ -2657,6 +2659,7 @@ void LLTextureFetch::commandSetRegion(const LLUUID & region_id) TFReqSetRegion * req = new TFReqSetRegion(region_id); cmdEnqueue(req); + LL_INFOS("Texture") << "COMMANDING SET REGION" << LL_ENDL; } void LLTextureFetch::commandSendMetrics(const std::string & caps_url, @@ -2683,7 +2686,7 @@ void LLTextureFetch::cmdEnqueue(TFRequest * req) mCommands.push_back(req); unlockQueue(); - wake(); + unpause(); } TFRequest * LLTextureFetch::cmdDequeue() @@ -2818,7 +2821,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats); // *TODO: Consider putting a report size limiter here. - + LL_INFOS("Texture") << "PROCESSING SENDMETRICS REQUEST" << LL_ENDL; if (! mCapsURL.empty()) { LLCurlRequest::headers_t headers; diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index d46d2da7bc..bad0a1498f 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -109,6 +109,7 @@ private: /*virtual*/ void startThread(void); /*virtual*/ void endThread(void); /*virtual*/ void threadedUpdate(void); + void commonUpdate(); // Metrics command helpers /** diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 79b45a459f..717ef40465 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1341,6 +1341,14 @@ void LLViewerRegion::unpackRegionHandshake() msg->nextBlock("RegionInfo"); msg->addU32("Flags", 0x0 ); msg->sendReliable(host); + + // Inform metrics when a region associated with an agent + // receives a regionID. + if (gAgent.getRegion() == this) + { + // Region is active in agent, tell metrics about the region ID + LLAppViewer::metricsUpdateRegion(region_id); + } } void LLViewerRegion::setSeedCapability(const std::string& url) -- cgit v1.3 From 0f2ed092c5712cd5dcd928e079671df383227068 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Mon, 29 Nov 2010 08:31:08 -0800 Subject: ESC-154 ESC-156 Now using region hash rather than region uuid as identifier. In the viewer, the region's UUID is acquired very late and isn't generally used as the canonical region identifier. The U64 region hash is a better and more consistently used identifier so I'm moving over to using that as the region key. Don't have a proper reserved invalid region hash which is unfortunate, but then, so much is. --- indra/newview/llagent.cpp | 2 +- indra/newview/llappviewer.cpp | 10 +-- indra/newview/llappviewer.h | 2 +- indra/newview/lltexturefetch.cpp | 18 ++--- indra/newview/lltexturefetch.h | 2 +- indra/newview/llviewerassetstats.cpp | 36 +++++----- indra/newview/llviewerassetstats.h | 31 +++++---- indra/newview/llviewerregion.cpp | 8 --- indra/newview/tests/llviewerassetstats_test.cpp | 88 +++++++++++++------------ 9 files changed, 102 insertions(+), 95 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index e2b1c89402..d5eec0e151 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -639,7 +639,7 @@ void LLAgent::setRegion(LLViewerRegion *regionp) } // Pass new region along to metrics components that care about this level of detail. - LLAppViewer::metricsUpdateRegion(regionp->getRegionID()); + LLAppViewer::metricsUpdateRegion(regionp->getHandle()); } mRegionp = regionp; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index bf79523078..d73f3cd2fc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4579,20 +4579,20 @@ bool LLAppViewer::getMasterSystemAudioMute() * on the main thread, we need to send a message to move the data over safely * and cheaply (amortized over a run). */ -void LLAppViewer::metricsUpdateRegion(const LLUUID & region_id) +void LLAppViewer::metricsUpdateRegion(U64 region_handle) { - if (! region_id.isNull()) + if (0 != region_handle) { - LLViewerAssetStatsFF::set_region_main(region_id); + LLViewerAssetStatsFF::set_region_main(region_handle); if (LLAppViewer::sTextureFetch) { // Send a region update message into 'thread1' to get the new region. - LLAppViewer::sTextureFetch->commandSetRegion(region_id); + LLAppViewer::sTextureFetch->commandSetRegion(region_handle); } else { // No 'thread1', a.k.a. TextureFetch, so update directly - LLViewerAssetStatsFF::set_region_thread1(region_id); + LLViewerAssetStatsFF::set_region_thread1(region_handle); } } } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 27c104626a..6b83f2d80c 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -169,7 +169,7 @@ public: virtual bool getMasterSystemAudioMute(); // Metrics policy helper statics. - static void metricsUpdateRegion(const LLUUID & region_id); + static void metricsUpdateRegion(U64 region_handle); static void metricsSend(bool enable_reporting); protected: diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index f5e2e35e1e..3793085e55 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -506,9 +506,9 @@ public: class TFReqSetRegion : public TFRequest { public: - TFReqSetRegion(const LLUUID & region_id) + TFReqSetRegion(U64 region_handle) : TFRequest(), - mRegionID(region_id) + mRegionHandle(region_handle) {} TFReqSetRegion & operator=(const TFReqSetRegion &); // Not defined @@ -518,7 +518,7 @@ public: virtual bool doWork(LLTextureFetch * fetcher); public: - const LLUUID mRegionID; + const U64 mRegionHandle; }; @@ -2654,9 +2654,9 @@ void LLTextureFetch::dump() // cross-thread command methods -void LLTextureFetch::commandSetRegion(const LLUUID & region_id) +void LLTextureFetch::commandSetRegion(U64 region_handle) { - TFReqSetRegion * req = new TFReqSetRegion(region_id); + TFReqSetRegion * req = new TFReqSetRegion(region_handle); cmdEnqueue(req); } @@ -2735,7 +2735,7 @@ namespace bool TFReqSetRegion::doWork(LLTextureFetch *) { - LLViewerAssetStatsFF::set_region_thread1(mRegionID); + LLViewerAssetStatsFF::set_region_thread1(mRegionHandle); return true; } @@ -2806,9 +2806,9 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) // still being careful, regardless. LLSD & main_stats = *mReportMain; - LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD(); // 'duration' & 'regions' from here - thread1_stats["message"] = "ViewerAssetMetrics"; - thread1_stats["sequence"] = report_sequence; + LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD(); // 'duration' & 'regions' from this LLSD + thread1_stats["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics + thread1_stats["sequence"] = report_sequence; // Sequence number thread1_stats["initial"] = ! reporting_started; // Initial data from viewer thread1_stats["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index bad0a1498f..03e2462058 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -86,7 +86,7 @@ public: LLTextureInfo* getTextureInfo() { return &mTextureInfo; } // Commands available to other threads to control metrics gathering operations. - void commandSetRegion(const LLUUID & region_id); + void commandSetRegion(U64 region_handle); void commandSendMetrics(const std::string & caps_url, LLSD * report_main); void commandDataBreak(); diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index 502a3aa340..cc41a95893 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -130,6 +130,7 @@ LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now) // LLViewerAssetStats class definition // ------------------------------------------------------ LLViewerAssetStats::LLViewerAssetStats() + : mRegionHandle(U64(0)) { reset(); } @@ -149,11 +150,11 @@ LLViewerAssetStats::reset() } else { - mCurRegionStats = new PerRegionStats(mRegionID); + mCurRegionStats = new PerRegionStats(mRegionHandle); } // And add reference to map - mRegionStats[mRegionID] = mCurRegionStats; + mRegionStats[mRegionHandle] = mCurRegionStats; // Start timestamp consistent with per-region collector mResetTimestamp = mCurRegionStats->mStartTimestamp; @@ -161,9 +162,9 @@ LLViewerAssetStats::reset() void -LLViewerAssetStats::setRegionID(const LLUUID & region_id) +LLViewerAssetStats::setRegion(region_handle_t region_handle) { - if (region_id == mRegionID) + if (region_handle == mRegionHandle) { // Already active, ignore. return; @@ -174,19 +175,19 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id) mCurRegionStats->accumulateTime(now); // Prepare new set - PerRegionContainer::iterator new_stats = mRegionStats.find(region_id); + PerRegionContainer::iterator new_stats = mRegionStats.find(region_handle); if (mRegionStats.end() == new_stats) { // Haven't seen this region_id before, create a new block and make it current. - mCurRegionStats = new PerRegionStats(region_id); - mRegionStats[region_id] = mCurRegionStats; + mCurRegionStats = new PerRegionStats(region_handle); + mRegionStats[region_handle] = mCurRegionStats; } else { mCurRegionStats = new_stats->second; } mCurRegionStats->mStartTimestamp = now; - mRegionID = region_id; + mRegionHandle = region_handle; } @@ -245,9 +246,9 @@ LLViewerAssetStats::asLLSD() mRegionStats.end() != it; ++it) { - if (it->first.isNull()) + if (0 == it->first) { - // Never emit NULL UUID in results. + // Never emit NULL UUID/handle in results. continue; } @@ -269,8 +270,11 @@ LLViewerAssetStats::asLLSD() } reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6); - - regions[it->first.asString()] = reg_stat; + std::stringstream reg_handle; + reg_handle.width(16); + reg_handle.fill('0'); + reg_handle << std::hex << it->first; + regions[reg_handle.str()] = reg_stat; } LLSD ret = LLSD::emptyMap(); @@ -487,12 +491,12 @@ namespace LLViewerAssetStatsFF // 'main' thread - initial program thread void -set_region_main(const LLUUID & region_id) +set_region_main(LLViewerAssetStats::region_handle_t region_handle) { if (! gViewerAssetStatsMain) return; - gViewerAssetStatsMain->setRegionID(region_id); + gViewerAssetStatsMain->setRegion(region_handle); } void @@ -526,12 +530,12 @@ record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, // 'thread1' - should be for TextureFetch thread void -set_region_thread1(const LLUUID & region_id) +set_region_thread1(LLViewerAssetStats::region_handle_t region_handle) { if (! gViewerAssetStatsThread1) return; - gViewerAssetStatsThread1->setRegionID(region_id); + gViewerAssetStatsThread1->setRegion(region_handle); } void diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index b0fb17ae17..ed2d0f3922 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -101,7 +101,14 @@ public: * fetcher class, LLTextureFetch. */ typedef U64 duration_t; - + + /** + * Type for the region identifier used in stats. Currently uses + * the region handle's type (a U64) rather than the regions's LLUUID + * as the latter isn't available immediately. + */ + typedef U64 region_handle_t; + /** * @brief Collected data for a single region visited by the avatar. * @@ -112,9 +119,9 @@ public: class PerRegionStats : public LLRefCount { public: - PerRegionStats(const LLUUID & region_id) + PerRegionStats(const region_handle_t region_handle) : LLRefCount(), - mRegionID(region_id) + mRegionHandle(region_handle) { reset(); } @@ -127,7 +134,7 @@ public: void accumulateTime(duration_t now); public: - LLUUID mRegionID; + region_handle_t mRegionHandle; duration_t mTotalTime; duration_t mStartTimestamp; @@ -151,14 +158,14 @@ public: // Set hidden region argument and establish context for subsequent // collection calls. - void setRegionID(const LLUUID & region_id); + void setRegion(region_handle_t region_handle); // Asset GET Requests void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp); void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp); void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration); - // Retrieve current metrics for all visited regions (NULL region UUID excluded) + // Retrieve current metrics for all visited regions (NULL region UUID/handle excluded) // Returned LLSD is structured as follows: // // &stats_group = { @@ -173,7 +180,7 @@ public: // { // duration: int // regions: { - // $: { + // $: { // Keys are strings of the region's handle in hex // duration: : int, // get_texture_temp_http : &stats_group, // get_texture_temp_udp : &stats_group, @@ -198,12 +205,12 @@ public: static void mergeRegionsLLSD(const LLSD & src, LLSD & dst); protected: - typedef std::map > PerRegionContainer; + typedef std::map > PerRegionContainer; // Region of the currently-active region. Always valid but may - // be a NULL UUID after construction or when explicitly set. Unchanged + // be zero after construction or when explicitly set. Unchanged // by a reset() call. - LLUUID mRegionID; + region_handle_t mRegionHandle; // Pointer to metrics collection for currently-active region. Always // valid and unchanged after reset() though contents will be changed. @@ -262,7 +269,7 @@ inline LLViewerAssetStats::duration_t get_timestamp() /** * Region context, event and duration loggers for the Main thread. */ -void set_region_main(const LLUUID & region_id); +void set_region_main(LLViewerAssetStats::region_handle_t region_handle); void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp); @@ -275,7 +282,7 @@ void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_t /** * Region context, event and duration loggers for Thread 1. */ -void set_region_thread1(const LLUUID & region_id); +void set_region_thread1(LLViewerAssetStats::region_handle_t region_handle); void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 717ef40465..79b45a459f 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1341,14 +1341,6 @@ void LLViewerRegion::unpackRegionHandshake() msg->nextBlock("RegionInfo"); msg->addU32("Flags", 0x0 ); msg->sendReliable(host); - - // Inform metrics when a region associated with an agent - // receives a regionID. - if (gAgent.getRegion() == this) - { - // Region is active in agent, tell metrics about the region ID - LLAppViewer::metricsUpdateRegion(region_id); - } } void LLViewerRegion::setSeedCapability(const std::string& url) diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 8bedd2c860..153056b3cd 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -78,6 +78,10 @@ static const char * sub_keys[] = static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8"); static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a"); +static const U64 region1_handle(0x00000401000003f7ULL); +static const U64 region2_handle(0x000003f800000420ULL); +static const std::string region1_handle_str("00000401000003f7"); +static const std::string region2_handle_str("000003f800000420"); #if 0 static bool @@ -144,12 +148,12 @@ namespace tut ensure("Stat-less LLSD initially", is_no_stats_map(sd_full)); // Once the region is set, we will get a response even with no data collection - it->setRegionID(region1); + it->setRegion(region1_handle); sd_full = it->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1.asString())); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1_handle_str)); - LLSD sd = sd_full["regions"][region1.asString()]; + LLSD sd = sd_full["regions"][region1_handle_str]; delete it; @@ -175,12 +179,12 @@ namespace tut void tst_viewerassetstats_index_object_t::test<3>() { LLViewerAssetStats * it = new LLViewerAssetStats(); - it->setRegionID(region1); + it->setRegion(region1_handle); LLSD sd = it->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); - sd = sd[region1.asString()]; + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd[region1_handle_str]; delete it; @@ -194,7 +198,7 @@ namespace tut void tst_viewerassetstats_index_object_t::test<4>() { gViewerAssetStatsMain = new LLViewerAssetStats(); - LLViewerAssetStatsFF::set_region_main(region1); + LLViewerAssetStatsFF::set_region_main(region1_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -204,8 +208,8 @@ namespace tut LLSD sd = gViewerAssetStatsMain->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); - sd = sd["regions"][region1.asString()]; + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd["regions"][region1_handle_str]; // Check a few points on the tree for content ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -217,7 +221,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()]; + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -232,7 +236,7 @@ namespace tut { gViewerAssetStatsThread1 = new LLViewerAssetStats(); gViewerAssetStatsMain = new LLViewerAssetStats(); - LLViewerAssetStatsFF::set_region_main(region1); + LLViewerAssetStatsFF::set_region_main(region1_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -244,8 +248,8 @@ namespace tut ensure("Other collector is empty", is_no_stats_map(sd)); sd = gViewerAssetStatsMain->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); - sd = sd["regions"][region1.asString()]; + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd["regions"][region1_handle_str]; // Check a few points on the tree for content ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -257,7 +261,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()]; + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -274,7 +278,7 @@ namespace tut { gViewerAssetStatsMain = new LLViewerAssetStats(); - LLViewerAssetStatsFF::set_region_main(region1); + LLViewerAssetStatsFF::set_region_main(region1_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -282,7 +286,7 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); - LLViewerAssetStatsFF::set_region_main(region2); + LLViewerAssetStatsFF::set_region_main(region2_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); @@ -294,9 +298,9 @@ namespace tut // std::cout << sd << std::endl; ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); - ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString())); - LLSD sd1 = sd["regions"][region1.asString()]; - LLSD sd2 = sd["regions"][region2.asString()]; + ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str)); + LLSD sd1 = sd["regions"][region1_handle_str]; + LLSD sd2 = sd["regions"][region2_handle_str]; // Check a few points on the tree for content ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -315,8 +319,8 @@ namespace tut gViewerAssetStatsMain->reset(); sd = gViewerAssetStatsMain->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString())); - sd2 = sd["regions"][region2.asString()]; + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str)); + sd2 = sd["regions"][region2_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -331,7 +335,7 @@ namespace tut { gViewerAssetStatsMain = new LLViewerAssetStats(); - LLViewerAssetStatsFF::set_region_main(region1); + LLViewerAssetStatsFF::set_region_main(region1_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -339,14 +343,14 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); - LLViewerAssetStatsFF::set_region_main(region2); + LLViewerAssetStatsFF::set_region_main(region2_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); - LLViewerAssetStatsFF::set_region_main(region1); + LLViewerAssetStatsFF::set_region_main(region1_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true); @@ -354,7 +358,7 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); - LLViewerAssetStatsFF::set_region_main(region2); + LLViewerAssetStatsFF::set_region_main(region2_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); @@ -364,9 +368,9 @@ namespace tut LLSD sd = gViewerAssetStatsMain->asLLSD(); ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); - ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString())); - LLSD sd1 = sd["regions"][region1.asString()]; - LLSD sd2 = sd["regions"][region2.asString()]; + ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str)); + LLSD sd1 = sd["regions"][region1_handle_str]; + LLSD sd2 = sd["regions"][region2_handle_str]; // Check a few points on the tree for content ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); @@ -385,8 +389,8 @@ namespace tut gViewerAssetStatsMain->reset(); sd = gViewerAssetStatsMain->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString())); - sd2 = sd["regions"][region2.asString()]; + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str)); + sd2 = sd["regions"][region2_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -401,7 +405,7 @@ namespace tut { gViewerAssetStatsThread1 = new LLViewerAssetStats(); gViewerAssetStatsMain = new LLViewerAssetStats(); - LLViewerAssetStatsFF::set_region_main(region1); + LLViewerAssetStatsFF::set_region_main(region1_handle); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); @@ -430,8 +434,8 @@ namespace tut ensure("Other collector is empty", is_no_stats_map(sd)); sd = gViewerAssetStatsMain->asLLSD(); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString())); - sd = sd["regions"][region1.asString()]; + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd["regions"][region1_handle_str]; // Check a few points on the tree for content ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger())); @@ -446,7 +450,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()]; + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -461,8 +465,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<9>() { - LLSD::String reg1_name = region1.asString(); - LLSD::String reg2_name = region2.asString(); + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; LLSD reg1_stats = LLSD::emptyMap(); LLSD reg2_stats = LLSD::emptyMap(); @@ -523,8 +527,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<10>() { - LLSD::String reg1_name = region1.asString(); - LLSD::String reg2_name = region2.asString(); + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; LLSD reg1_stats = LLSD::emptyMap(); LLSD reg2_stats = LLSD::emptyMap(); @@ -580,8 +584,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<11>() { - LLSD::String reg1_name = region1.asString(); - LLSD::String reg2_name = region2.asString(); + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; LLSD reg1_stats = LLSD::emptyMap(); LLSD reg2_stats = LLSD::emptyMap(); @@ -637,8 +641,8 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<12>() { - LLSD::String reg1_name = region1.asString(); - LLSD::String reg2_name = region2.asString(); + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; LLSD reg1_stats = LLSD::emptyMap(); LLSD reg2_stats = LLSD::emptyMap(); -- cgit v1.3 From 18dbbb4fa45fae8fc9d74eb040308e96abd9e749 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Wed, 1 Dec 2010 14:42:12 -0800 Subject: download progress events. --- indra/newview/llappviewer.cpp | 1 - .../updater/llupdatedownloader.cpp | 44 ++++++++++++++++++++++ indra/viewer_components/updater/llupdaterservice.h | 3 +- 3 files changed, 46 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b6f52e3e15..aa20ff55b6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2402,7 +2402,6 @@ namespace { LLNotificationsUtil::add("FailedUpdateInstall"); break; default: - llinfos << "unhandled update event " << evt << llendl; break; } diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index c17a50e242..7b0f960ce4 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -29,6 +29,7 @@ #include #include #include "lldir.h" +#include "llevents.h" #include "llfile.h" #include "llmd5.h" #include "llsd.h" @@ -49,6 +50,7 @@ public: bool isDownloading(void); size_t onHeader(void * header, size_t size); size_t onBody(void * header, size_t size); + int onProgress(double downloadSize, double bytesDownloaded); void resume(void); private: @@ -57,6 +59,7 @@ private: CURL * mCurl; LLSD mDownloadData; llofstream mDownloadStream; + unsigned char mDownloadPercent; std::string mDownloadRecordPath; curl_slist * mHeaderList; @@ -149,6 +152,17 @@ namespace { size_t bytes = blockSize * blocks; return reinterpret_cast(downloader)->onHeader(data, bytes); } + + + int progress_callback(void * downloader, + double dowloadTotal, + double downloadNow, + double uploadTotal, + double uploadNow) + { + return reinterpret_cast(downloader)-> + onProgress(dowloadTotal, downloadNow); + } } @@ -157,6 +171,7 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & mCancelled(false), mClient(client), mCurl(0), + mDownloadPercent(0), mHeaderList(0) { CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. @@ -290,6 +305,30 @@ size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) } +int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double bytesDownloaded) +{ + int downloadPercent = static_cast(100. * (bytesDownloaded / downloadSize)); + if(downloadPercent > mDownloadPercent) { + mDownloadPercent = downloadPercent; + + LLSD event; + event["pump"] = LLUpdaterService::pumpName(); + LLSD payload; + payload["type"] = LLSD(LLUpdaterService::PROGRESS); + payload["download_size"] = downloadSize; + payload["bytes_downloaded"] = bytesDownloaded; + event["payload"] = payload; + LLEventPumps::instance().obtain("mainlooprepeater").post(event); + + LL_INFOS("UpdateDownload") << "progress event " << payload << LL_ENDL; + } else { + ; // Keep events to a reasonalbe number. + } + + return 0; +} + + void LLUpdateDownloader::Implementation::run(void) { CURLcode code = curl_easy_perform(mCurl); @@ -343,6 +382,11 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u } throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true)); throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str())); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false)); + + mDownloadPercent = 0; } diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 752a6f834b..1266bcae08 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -48,7 +48,8 @@ public: INVALID, DOWNLOAD_COMPLETE, DOWNLOAD_ERROR, - INSTALL_ERROR + INSTALL_ERROR, + PROGRESS }; LLUpdaterService(); -- cgit v1.3 From 2a92d622d710ec4f83b3c9b5568d508067bf7107 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Mon, 6 Dec 2010 16:42:06 -0800 Subject: CHOP-257 - programmer XUI for update ready to install. One tip, one alert. Rev. by Brad --- indra/newview/llappviewer.cpp | 2 +- indra/newview/skins/default/xui/en/notifications.xml | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 63b2fcefd7..31115a4218 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2396,7 +2396,7 @@ namespace { switch (evt["type"].asInteger()) { case LLUpdaterService::DOWNLOAD_COMPLETE: - LLNotificationsUtil::add("DownloadBackground"); + LLNotificationsUtil::add("DownloadBackgroundDialog"); break; case LLUpdaterService::INSTALL_ERROR: LLNotificationsUtil::add("FailedUpdateInstall"); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 60b876d163..2d635bab76 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2887,12 +2887,29 @@ http://secondlife.com/download. name="okbutton" yestext="OK"/> + An updated version of [APP_NAME] has been downloaded. It will be applied the next time you restart [APP_NAME] + + + + + An updated version of [APP_NAME] has been downloaded. + It will be applied the next time you restart [APP_NAME] + Date: Tue, 7 Dec 2010 10:35:37 -0800 Subject: login instance coordinates with updater service --- indra/newview/llappviewer.cpp | 5 + indra/newview/lllogininstance.cpp | 381 ++++++++++++++++++++- indra/newview/lllogininstance.h | 3 + .../newview/skins/default/xui/en/notifications.xml | 13 + indra/newview/tests/lllogininstance_test.cpp | 38 ++ 5 files changed, 439 insertions(+), 1 deletion(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 63b2fcefd7..f45bc474fc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -80,6 +80,7 @@ #include "llfeaturemanager.h" #include "llurlmatch.h" #include "lltextutil.h" +#include "lllogininstance.h" #include "llweb.h" #include "llsecondlifeurls.h" @@ -590,10 +591,14 @@ LLAppViewer::LLAppViewer() : setupErrorHandling(); sInstance = this; gLoggedInTime.stop(); + + LLLoginInstance::instance().setUpdaterService(mUpdater.get()); } LLAppViewer::~LLAppViewer() { + LLLoginInstance::instance().setUpdaterService(0); + destroyMainloopTimeout(); // If we got to this destructor somehow, the app didn't hang. diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 52ce932241..f6338ac50e 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -55,12 +55,382 @@ #include "llsecapi.h" #include "llstartup.h" #include "llmachineid.h" +#include "llupdaterservice.h" +#include "llevents.h" +#include "llnotificationsutil.h" +#include "llappviewer.h" + +#include + +namespace { + class MandatoryUpdateMachine { + public: + MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService); + + void start(void); + + private: + class State; + class CheckingForUpdate; + class Error; + class ReadyToInstall; + class StartingUpdaterService; + class WaitingForDownload; + + LLLoginInstance & mLoginInstance; + boost::scoped_ptr mState; + LLUpdaterService & mUpdaterService; + + void setCurrentState(State * newState); + }; + + + class MandatoryUpdateMachine::State { + public: + virtual ~State() {} + virtual void enter(void) {} + virtual void exit(void) {} + }; + + + class MandatoryUpdateMachine::CheckingForUpdate: + public MandatoryUpdateMachine::State + { + public: + CheckingForUpdate(MandatoryUpdateMachine & machine); + + virtual void enter(void); + virtual void exit(void); + + private: + LLTempBoundListener mConnection; + MandatoryUpdateMachine & mMachine; + + bool onEvent(LLSD const & event); + }; + + + class MandatoryUpdateMachine::Error: + public MandatoryUpdateMachine::State + { + public: + Error(MandatoryUpdateMachine & machine); + + virtual void enter(void); + virtual void exit(void); + void onButtonClicked(const LLSD &, const LLSD &); + + private: + MandatoryUpdateMachine & mMachine; + }; + + + class MandatoryUpdateMachine::ReadyToInstall: + public MandatoryUpdateMachine::State + { + public: + ReadyToInstall(MandatoryUpdateMachine & machine); + + virtual void enter(void); + virtual void exit(void); + + private: + MandatoryUpdateMachine & mMachine; + }; + + + class MandatoryUpdateMachine::StartingUpdaterService: + public MandatoryUpdateMachine::State + { + public: + StartingUpdaterService(MandatoryUpdateMachine & machine); + + virtual void enter(void); + virtual void exit(void); + void onButtonClicked(const LLSD & uiform, const LLSD & result); + private: + MandatoryUpdateMachine & mMachine; + }; + + + class MandatoryUpdateMachine::WaitingForDownload: + public MandatoryUpdateMachine::State + { + public: + WaitingForDownload(MandatoryUpdateMachine & machine); + + virtual void enter(void); + virtual void exit(void); + + private: + LLTempBoundListener mConnection; + MandatoryUpdateMachine & mMachine; + + bool onEvent(LLSD const & event); + }; +} static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback"; static const char * const TOS_LISTENER_NAME = "lllogininstance_tos"; std::string construct_start_string(); + + +// MandatoryUpdateMachine +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService): + mLoginInstance(loginInstance), + mUpdaterService(updaterService) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::start(void) +{ + llinfos << "starting manditory update machine" << llendl; + + if(mUpdaterService.isChecking()) { + switch(mUpdaterService.getState()) { + case LLUpdaterService::UP_TO_DATE: + mUpdaterService.stopChecking(); + mUpdaterService.startChecking(); + // Fall through. + case LLUpdaterService::INITIAL: + case LLUpdaterService::CHECKING_FOR_UPDATE: + setCurrentState(new CheckingForUpdate(*this)); + break; + case LLUpdaterService::DOWNLOADING: + setCurrentState(new WaitingForDownload(*this)); + break; + case LLUpdaterService::TERMINAL: + if(LLUpdaterService::updateReadyToInstall()) { + setCurrentState(new ReadyToInstall(*this)); + } else { + setCurrentState(new Error(*this)); + } + break; + case LLUpdaterService::ERROR: + setCurrentState(new Error(*this)); + break; + default: + llassert(!"unpossible case"); + break; + } + } else { + setCurrentState(new StartingUpdaterService(*this)); + } +} + + +void MandatoryUpdateMachine::setCurrentState(State * newStatePointer) +{ + { + boost::scoped_ptr newState(newStatePointer); + if(mState != 0) mState->exit(); + mState.swap(newState); + + // Old state will be deleted on exit from this block before the new state + // is entered. + } + if(mState != 0) mState->enter(); +} + + + +// MandatoryUpdateMachine::CheckingForUpdate +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine): + mMachine(machine) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::CheckingForUpdate::enter(void) +{ + llinfos << "entering checking for update" << llendl; + + mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). + listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1)); +} + + +void MandatoryUpdateMachine::CheckingForUpdate::exit(void) +{ +} + + +bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event) +{ + if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) { + switch(event["state"].asInteger()) { + case LLUpdaterService::DOWNLOADING: + mMachine.setCurrentState(new WaitingForDownload(mMachine)); + break; + case LLUpdaterService::UP_TO_DATE: + case LLUpdaterService::TERMINAL: + case LLUpdaterService::ERROR: + mMachine.setCurrentState(new Error(mMachine)); + break; + case LLUpdaterService::INSTALLING: + llassert(!"can't possibly be installing"); + break; + default: + break; + } + } else { + ; // Ignore. + } + + return false; +} + + + +// MandatoryUpdateMachine::Error +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine): + mMachine(machine) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::Error::enter(void) +{ + llinfos << "entering error" << llendl; + LLNotificationsUtil::add("FailedUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2)); +} + + +void MandatoryUpdateMachine::Error::exit(void) +{ + LLAppViewer::instance()->forceQuit(); +} + + +void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &) +{ + mMachine.setCurrentState(0); +} + + + +// MandatoryUpdateMachine::ReadyToInstall +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine): + mMachine(machine) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::ReadyToInstall::enter(void) +{ + llinfos << "entering ready to install" << llendl; + // Open update ready dialog. +} + + +void MandatoryUpdateMachine::ReadyToInstall::exit(void) +{ + // Restart viewer. +} + + + +// MandatoryUpdateMachine::StartingUpdaterService +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine): + mMachine(machine) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::StartingUpdaterService::enter(void) +{ + llinfos << "entering start update service" << llendl; + LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2)); +} + + +void MandatoryUpdateMachine::StartingUpdaterService::exit(void) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result) +{ + if(result["OK_okcancelbuttons"].asBoolean()) { + mMachine.mUpdaterService.startChecking(false); + mMachine.setCurrentState(new CheckingForUpdate(mMachine)); + } else { + LLAppViewer::instance()->forceQuit(); + } +} + + + +// MandatoryUpdateMachine::WaitingForDownload +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine): + mMachine(machine) +{ + ; // No op. +} + + +void MandatoryUpdateMachine::WaitingForDownload::enter(void) +{ + llinfos << "entering waiting for download" << llendl; + mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). + listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1)); +} + + +void MandatoryUpdateMachine::WaitingForDownload::exit(void) +{ +} + + +bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event) +{ + switch(event["type"].asInteger()) { + case LLUpdaterService::DOWNLOAD_COMPLETE: + mMachine.setCurrentState(new ReadyToInstall(mMachine)); + break; + case LLUpdaterService::DOWNLOAD_ERROR: + mMachine.setCurrentState(new Error(mMachine)); + break; + default: + break; + } + + return false; +} + + + +// LLLoginInstance +//----------------------------------------------------------------------------- + + LLLoginInstance::LLLoginInstance() : mLoginModule(new LLLogin()), mNotifications(NULL), @@ -69,7 +439,8 @@ LLLoginInstance::LLLoginInstance() : mSkipOptionalUpdate(false), mAttemptComplete(false), mTransferRate(0.0f), - mDispatcher("LLLoginInstance", "change") + mDispatcher("LLLoginInstance", "change"), + mUpdaterService(0) { mLoginModule->getEventPump().listen("lllogininstance", boost::bind(&LLLoginInstance::handleLoginEvent, this, _1)); @@ -353,6 +724,14 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key) void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg) { + if(mandatory) + { + gViewerWindow->setShowProgress(false); + MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService); + machine->start(); + return; + } + // store off config state, as we might quit soon gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); LLUIColorTable::instance().saveUserSettings(); diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index 159e05046c..cb1f56a971 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -34,6 +34,7 @@ class LLLogin; class LLEventStream; class LLNotificationsInterface; +class LLUpdaterService; // This class hosts the login module and is used to // negotiate user authentication attempts. @@ -75,6 +76,7 @@ public: typedef boost::function UpdaterLauncherCallback; void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; } + void setUpdaterService(LLUpdaterService * updaterService) { mUpdaterService = updaterService; } private: void constructAuthParams(LLPointer user_credentials); void updateApp(bool mandatory, const std::string& message); @@ -104,6 +106,7 @@ private: int mLastExecEvent; UpdaterLauncherCallback mUpdaterLauncher; LLEventDispatcher mDispatcher; + LLUpdaterService * mUpdaterService; }; #endif diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 60b876d163..bac1ad18d9 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2887,6 +2887,19 @@ http://secondlife.com/download. name="okbutton" yestext="OK"/> + + +An update is required to log in. May we start the background +updater service to fetch and install the update? + + + functor) { return LLNotificationPtr((LLNotification*)0); } + + +//----------------------------------------------------------------------------- +#include "llupdaterservice.h" + +std::string const & LLUpdaterService::pumpName(void) +{ + static std::string wakka = "wakka wakka wakka"; + return wakka; +} +bool LLUpdaterService::updateReadyToInstall(void) { return false; } +void LLUpdaterService::initialize(const std::string& protocol_version, + const std::string& url, + const std::string& path, + const std::string& channel, + const std::string& version) {} + +void LLUpdaterService::setCheckPeriod(unsigned int seconds) {} +void LLUpdaterService::startChecking(bool install_if_ready) {} +void LLUpdaterService::stopChecking() {} +bool LLUpdaterService::isChecking() { return false; } +LLUpdaterService::eUpdaterState LLUpdaterService::getState() { return INITIAL; } + //----------------------------------------------------------------------------- #include "llnotifications.h" #include "llfloaterreg.h" @@ -435,6 +469,8 @@ namespace tut template<> template<> void lllogininstance_object::test<3>() { + skip(); + set_test_name("Test Mandatory Update User Accepts"); // Part 1 - Mandatory Update, with User accepts response. @@ -462,6 +498,8 @@ namespace tut template<> template<> void lllogininstance_object::test<4>() { + skip(); + set_test_name("Test Mandatory Update User Decline"); // Test connect with update needed. -- cgit v1.3 From 3c3683b884542e5aa85099f4ce0c1b556613795d Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 7 Dec 2010 15:41:31 -0800 Subject: limit dowload bandwidth to 'Maximum bandwidth' setting --- indra/newview/llappviewer.cpp | 9 ++++++++ .../updater/llupdatedownloader.cpp | 26 ++++++++++++++++++++++ .../viewer_components/updater/llupdatedownloader.h | 3 +++ .../viewer_components/updater/llupdaterservice.cpp | 11 +++++++++ indra/viewer_components/updater/llupdaterservice.h | 1 + .../updater/tests/llupdaterservice_test.cpp | 1 + 6 files changed, 51 insertions(+) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 08e40168c3..38422621ef 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2413,6 +2413,12 @@ namespace { // let others also handle this event by default return false; } + + bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt) + { + updater->setBandwidthLimit(evt.asInteger() * (1024/8)); + return false; // Let others receive this event. + }; }; void LLAppViewer::initUpdater() @@ -2435,6 +2441,9 @@ void LLAppViewer::initUpdater() channel, version); mUpdater->setCheckPeriod(check_period); + mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("ThrottleBandwidthKBPS") * (1024/8)); + gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()-> + connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2)); if(gSavedSettings.getBOOL("UpdaterServiceActive")) { bool install_if_ready = true; diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index ce6b488ecb..d67de1c83b 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -54,8 +54,10 @@ public: size_t onBody(void * header, size_t size); int onProgress(double downloadSize, double bytesDownloaded); void resume(void); + void setBandwidthLimit(U64 bytesPerSecond); private: + curl_off_t mBandwidthLimit; bool mCancelled; LLUpdateDownloader::Client & mClient; CURL * mCurl; @@ -136,6 +138,12 @@ void LLUpdateDownloader::resume(void) } +void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) +{ + mImplementation->setBandwidthLimit(bytesPerSecond); +} + + // LLUpdateDownloader::Implementation //----------------------------------------------------------------------------- @@ -170,6 +178,7 @@ namespace { LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client): LLThread("LLUpdateDownloader"), + mBandwidthLimit(0), mCancelled(false), mClient(client), mCurl(0), @@ -264,6 +273,20 @@ void LLUpdateDownloader::Implementation::resume(void) } +void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond) +{ + if((mBandwidthLimit != bytesPerSecond) && isDownloading()) { + llassert(mCurl != 0); + mBandwidthLimit = bytesPerSecond; + CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit); + if(code != CURLE_OK) LL_WARNS("UpdateDownload") << + "unable to change dowload bandwidth" << LL_ENDL; + } else { + mBandwidthLimit = bytesPerSecond; + } +} + + size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) { char const * headerPtr = reinterpret_cast (buffer); @@ -388,6 +411,9 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback)); throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this)); throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false)); + if(mBandwidthLimit != 0) { + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, mBandwidthLimit)); + } mDownloadPercent = 0; } diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index 09ea1676d5..4e20b307b8 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -60,6 +60,9 @@ public: // Resume a partial download. void resume(void); + // Set a limit on the dowload rate. + void setBandwidthLimit(U64 bytesPerSecond); + private: boost::shared_ptr mImplementation; }; diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index 7d180ff649..b29356b968 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -114,6 +114,7 @@ public: const std::string& version); void setCheckPeriod(unsigned int seconds); + void setBandwidthLimit(U64 bytesPerSecond); void startChecking(bool install_if_ready); void stopChecking(); @@ -189,6 +190,11 @@ void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds) mCheckPeriod = seconds; } +void LLUpdaterServiceImpl::setBandwidthLimit(U64 bytesPerSecond) +{ + mUpdateDownloader.setBandwidthLimit(bytesPerSecond); +} + void LLUpdaterServiceImpl::startChecking(bool install_if_ready) { if(mUrl.empty() || mChannel.empty() || mVersion.empty()) @@ -541,6 +547,11 @@ void LLUpdaterService::setCheckPeriod(unsigned int seconds) { mImpl->setCheckPeriod(seconds); } + +void LLUpdaterService::setBandwidthLimit(U64 bytesPerSecond) +{ + mImpl->setBandwidthLimit(bytesPerSecond); +} void LLUpdaterService::startChecking(bool install_if_ready) { diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 8b76a9d1e7..1ffa609019 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -76,6 +76,7 @@ public: const std::string& version); void setCheckPeriod(unsigned int seconds); + void setBandwidthLimit(U64 bytesPerSecond); void startChecking(bool install_if_ready = false); void stopChecking(); diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 050bb774f7..fbdf9a4993 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -101,6 +101,7 @@ std::string LLUpdateDownloader::downloadMarkerPath(void) void LLUpdateDownloader::resume(void) {} void LLUpdateDownloader::cancel(void) {} +void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {} int ll_install_update(std::string const &, std::string const &, LLInstallScriptMode) { -- cgit v1.3 From 337f95f8b92d5efd0aaf4e955244ddbeae437bf1 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 7 Dec 2010 16:20:19 -0800 Subject: lamo programmer ui for setting downloader bandwidth limit. --- indra/newview/app_settings/settings.xml | 11 ++++++++ indra/newview/llappviewer.cpp | 4 +-- .../default/xui/en/panel_preferences_setup.xml | 32 ++++++++++++++++++++-- 3 files changed, 42 insertions(+), 5 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7dbb375a20..33a48164b0 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9990,6 +9990,17 @@ Value 500.0 + UpdaterMaximumBandwidth + + Comment + Maximum allowable downstream bandwidth for updater service (kilo bits per second) + Persist + 1 + Type + F32 + Value + 500.0 + ToolTipDelay Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 38422621ef..3943ab0f30 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2441,8 +2441,8 @@ void LLAppViewer::initUpdater() channel, version); mUpdater->setCheckPeriod(check_period); - mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("ThrottleBandwidthKBPS") * (1024/8)); - gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()-> + mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8)); + gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()-> connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2)); if(gSavedSettings.getBOOL("UpdaterServiceActive")) { diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 584bd1ea9d..b551901a56 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -142,7 +142,7 @@ layout="topleft" left="80" name="Cache location" - top_delta="40" + top_delta="20" width="300"> Cache location: @@ -341,7 +341,6 @@ name="web_proxy_port" top_delta="0" width="145" /> - - + +Download bandwidth + + -- cgit v1.3 From d9fad868ed5fb53522dde44f084c299df0429d53 Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Wed, 8 Dec 2010 15:54:50 -0800 Subject: Fix for CHOP-262 (update notifications prior to login) and first attempt at CHOP-261 (add handlers for update ready notification buttons) reviewed by mani. --- indra/newview/llappviewer.cpp | 28 ++++++++++++++++++++-- .../newview/skins/default/xui/en/notifications.xml | 4 ++-- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3943ab0f30..b852b63cf8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2394,14 +2394,38 @@ bool LLAppViewer::initConfiguration() } namespace { - // *TODO - decide if there's a better place for this function. + // *TODO - decide if there's a better place for these functions. // do we need a file llupdaterui.cpp or something? -brad + + void apply_update_callback(LLSD const & notification, LLSD const & response) + { + lldebugs << "LLUpdate user response: " << response << llendl; + if(response["OK_okcancelbuttons"].asBoolean()) + { + llinfos << "LLUpdate restarting viewer" << llendl; + static const bool install_if_ready = true; + // *HACK - this lets us launch the installer immediately for now + LLUpdaterService().startChecking(install_if_ready); + } + } + bool notify_update(LLSD const & evt) { + std::string notification_name; switch (evt["type"].asInteger()) { case LLUpdaterService::DOWNLOAD_COMPLETE: - LLNotificationsUtil::add("DownloadBackgroundDialog"); + if(LLStartUp::getStartupState() < STATE_STARTED) + { + // CHOP-262 we need to use a different notification + // method prior to login. + notification_name = "DownloadBackgroundDialog"; + } + else + { + notification_name = "DownloadBackgroundTip"; + } + LLNotificationsUtil::add(notification_name, LLSD(), LLSD(), apply_update_callback); break; case LLUpdaterService::INSTALL_ERROR: LLNotificationsUtil::add("FailedUpdateInstall"); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index e333c891a4..8c76231595 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2901,9 +2901,9 @@ updater service to fetch and install the update? + type="notify"> An updated version of [APP_NAME] has been downloaded. It will be applied the next time you restart [APP_NAME] Date: Thu, 9 Dec 2010 12:49:51 -0800 Subject: change updater settings from check box to drop down menu; add choice of whether to install automatically as well as download automatically (not actually implemented yet). --- indra/newview/app_settings/settings.xml | 8 +-- indra/newview/llappviewer.cpp | 2 +- indra/newview/llviewercontrol.cpp | 4 +- .../default/xui/en/panel_preferences_setup.xml | 73 ++++++++++------------ 4 files changed, 40 insertions(+), 47 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 33a48164b0..5d89051c45 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11101,16 +11101,16 @@ Value 15 - UpdaterServiceActive + UpdaterServiceSetting Comment - Enable or disable the updater service. + Configure updater service. Persist 1 Type - Boolean + U32 Value - 1 + 3 UpdaterServiceCheckPeriod diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b852b63cf8..1306e92b35 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2468,7 +2468,7 @@ void LLAppViewer::initUpdater() mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8)); gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()-> connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2)); - if(gSavedSettings.getBOOL("UpdaterServiceActive")) + if(gSavedSettings.getU32("UpdaterServiceSetting")) { bool install_if_ready = true; mUpdater->startChecking(install_if_ready); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 622d09c600..2c75551285 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -504,7 +504,7 @@ bool toggle_show_object_render_cost(const LLSD& newvalue) void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value) { - if(new_value.asBoolean()) + if(new_value.asInteger()) { LLUpdaterService().startChecking(); } @@ -661,7 +661,7 @@ void settings_setup_listeners() gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2)); gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2)); gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2)); - gSavedSettings.getControl("UpdaterServiceActive")->getSignal()->connect(&toggle_updater_service_active); + gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(&toggle_updater_service_active); gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2)); gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2)); } diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index b551901a56..542b6bcf6b 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -341,46 +341,39 @@ name="web_proxy_port" top_delta="0" width="145" /> - -Download bandwidth + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="30" + name="Software updates:" + mouse_opaque="false" + top_pad="5" + width="300"> + Software updates: - + + + + + -- cgit v1.3 From 90da762f97a30c16e23184352f4d413c34279ba4 Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Thu, 9 Dec 2010 18:04:03 -0800 Subject: CHOP-265 Fixed up LL_SEND_CRASH_REPORTS usage. Reviewed by Brad. --- build.sh | 3 ++- indra/cmake/00-Common.cmake | 27 ++++++++++++++------------- indra/newview/CMakeLists.txt | 40 +++++++++++++++++++++------------------- indra/newview/llappviewer.cpp | 2 ++ 4 files changed, 39 insertions(+), 33 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/build.sh b/build.sh index f9c6beefed..c5f74c23ee 100755 --- a/build.sh +++ b/build.sh @@ -59,10 +59,11 @@ pre_build() -t $variant \ -G "$cmake_generator" \ configure \ - -DGRID:STRING="$viewer_grid" \ + -DGRID:STRING="$viewer_grid" \ -DVIEWER_CHANNEL:STRING="$viewer_channel" \ -DVIEWER_LOGIN_CHANNEL:STRING="$login_channel" \ -DINSTALL_PROPRIETARY:BOOL=ON \ + -DRELEASE_CRASH_REPORTING:BOOL=ON \ -DLOCALIZESETUP:BOOL=ON \ -DPACKAGE:BOOL=ON \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index db2cdb5ff8..dbe0cf5cd0 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -4,27 +4,28 @@ include(Variables) - # Portable compilation flags. - -if (EXISTS ${CMAKE_SOURCE_DIR}/llphysics) - # The release build should only offer to send crash reports if we're - # building from a Linden internal source tree. - set(release_crash_reports 1) -else (EXISTS ${CMAKE_SOURCE_DIR}/llphysics) - set(release_crash_reports 0) -endif (EXISTS ${CMAKE_SOURCE_DIR}/llphysics) - set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1") set(CMAKE_CXX_FLAGS_RELEASE - "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=${release_crash_reports} -DNDEBUG") + "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DNDEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") + "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") +# Configure crash reporting +set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds") +set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds") -# Don't bother with a MinSizeRel build. +if(RELEASE_CRASH_REPORTING) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DLL_SEND_CRASH_REPORTS=1") +endif() + +if(NON_RELEASE_CRASH_REPORTING) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLL_SEND_CRASH_REPORTS=1") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1") +endif() +# Don't bother with a MinSizeRel build. set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "Supported build types." FORCE) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 679637caf6..1a3f274664 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1843,29 +1843,31 @@ if (PACKAGE) set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) endif (LINUX) - if(CMAKE_CFG_INTDIR STREQUAL ".") + if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) + if(CMAKE_CFG_INTDIR STREQUAL ".") set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) - else(CMAKE_CFG_INTDIR STREQUAL ".") + else(CMAKE_CFG_INTDIR STREQUAL ".") # set LLBUILD_CONFIG to be a shell variable evaluated at build time # reflecting the configuration we are currently building. set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) - endif(CMAKE_CFG_INTDIR STREQUAL ".") - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - COMMAND "${PYTHON_EXECUTABLE}" - ARGS - "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" - "${LLBUILD_CONFIG}" - "${VIEWER_DIST_DIR}" - "${VIEWER_EXE_GLOBS}" - "${VIEWER_LIB_GLOB}" - "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" - "${VIEWER_SYMBOL_FILE}" - DEPENDS generate_breakpad_symbols.py - VERBATIM - ) - add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") - add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") - add_dependencies(package generate_breakpad_symbols) + endif(CMAKE_CFG_INTDIR STREQUAL ".") + add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" + COMMAND "${PYTHON_EXECUTABLE}" + ARGS + "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" + "${LLBUILD_CONFIG}" + "${VIEWER_DIST_DIR}" + "${VIEWER_EXE_GLOBS}" + "${VIEWER_LIB_GLOB}" + "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" + "${VIEWER_SYMBOL_FILE}" + DEPENDS generate_breakpad_symbols.py + VERBATIM) + + add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") + add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") + add_dependencies(package generate_breakpad_symbols) + endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) endif (PACKAGE) if (LL_TESTS) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6c07974f69..8e16398390 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2858,8 +2858,10 @@ void LLAppViewer::handleViewerCrash() pApp->removeMarkerFile(false); } +#if LL_SEND_CRASH_REPORTS // Call to pure virtual, handled by platform specific llappviewer instance. pApp->handleCrashReporting(); +#endif return; } -- cgit v1.3 From b89b41991e49e24b826d1b44ebfe3587a8b248ab Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Fri, 10 Dec 2010 09:43:01 -0800 Subject: ui improvements to more closely match UX design. --- indra/newview/llappviewer.cpp | 52 +++++++++++++++++++--- indra/newview/lllogininstance.cpp | 8 +++- .../newview/skins/default/xui/en/notifications.xml | 38 +++++++++++++--- indra/newview/tests/lllogininstance_test.cpp | 1 + .../viewer_components/updater/llupdaterservice.cpp | 17 +++++++ indra/viewer_components/updater/llupdaterservice.h | 5 +++ 6 files changed, 107 insertions(+), 14 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1306e92b35..41be4eb065 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2408,6 +2408,49 @@ namespace { LLUpdaterService().startChecking(install_if_ready); } } + + void apply_update_ok_callback(LLSD const & notification, LLSD const & response) + { + llinfos << "LLUpdate restarting viewer" << llendl; + static const bool install_if_ready = true; + // *HACK - this lets us launch the installer immediately for now + LLUpdaterService().startChecking(install_if_ready); + } + + void on_required_update_downloaded(LLSD const & data) + { + std::string notification_name; + if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) + { + // The user never saw the progress bar. + notification_name = "RequiredUpdateDownloadedVerboseDialog"; + } + else + { + notification_name = "RequiredUpdateDownloadedDialog"; + } + LLSD substitutions; + substitutions["VERSION"] = data["version"]; + LLNotificationsUtil::add(notification_name, substitutions, LLSD(), &apply_update_ok_callback); + } + + void on_optional_update_downloaded(LLSD const & data) + { + std::string notification_name; + if(LLStartUp::getStartupState() < STATE_STARTED) + { + // CHOP-262 we need to use a different notification + // method prior to login. + notification_name = "DownloadBackgroundDialog"; + } + else + { + notification_name = "DownloadBackgroundTip"; + } + LLSD substitutions; + substitutions["VERSION"] = data["version"]; + LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_update_callback); + } bool notify_update(LLSD const & evt) { @@ -2415,17 +2458,14 @@ namespace { switch (evt["type"].asInteger()) { case LLUpdaterService::DOWNLOAD_COMPLETE: - if(LLStartUp::getStartupState() < STATE_STARTED) + if(evt["required"].asBoolean()) { - // CHOP-262 we need to use a different notification - // method prior to login. - notification_name = "DownloadBackgroundDialog"; + on_required_update_downloaded(evt); } else { - notification_name = "DownloadBackgroundTip"; + on_optional_update_downloaded(evt); } - LLNotificationsUtil::add(notification_name, LLSD(), LLSD(), apply_update_callback); break; case LLUpdaterService::INSTALL_ERROR: LLNotificationsUtil::add("FailedUpdateInstall"); diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 3ff1487286..1858cbdcd9 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -62,6 +62,7 @@ #include "llappviewer.h" #include +#include namespace { class MandatoryUpdateMachine { @@ -261,7 +262,7 @@ void MandatoryUpdateMachine::CheckingForUpdate::enter(void) mProgressView = gViewerWindow->getProgressView(); mProgressView->setMessage("Looking for update..."); - mProgressView->setText("Update"); + mProgressView->setText("There is a required update for your Second Life installation."); mProgressView->setPercent(0); mProgressView->setVisible(true); mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). @@ -411,7 +412,10 @@ void MandatoryUpdateMachine::WaitingForDownload::enter(void) llinfos << "entering waiting for download" << llendl; mProgressView = gViewerWindow->getProgressView(); mProgressView->setMessage("Downloading update..."); - mProgressView->setText("Update"); + std::ostringstream stream; + stream << "There is a required update for your Second Life installation." << std::endl << + "Version " << mMachine.mUpdaterService.updatedVersion(); + mProgressView->setText(stream.str()); mProgressView->setPercent(0); mProgressView->setVisible(true); mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 80a210f9bc..eecbeeb8dc 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2893,6 +2893,9 @@ http://secondlife.com/download. name="UpdaterServiceNotRunning" type="alertmodal"> There is a required update for your Second Life Installation. + +You may download this update from http://www.secondlife.com/downloads +or you can install it now. -An updated version of [APP_NAME] has been downloaded. -It will be applied the next time you restart [APP_NAME] +We have downloaded and update to your [APP_NAME] installation. +Version [VERSION] - An updated version of [APP_NAME] has been downloaded. - It will be applied the next time you restart [APP_NAME] +We have downloaded and update to your [APP_NAME] installation. +Version [VERSION] + notext="Later..." + yestext="Install now and restart [APP_NAME]"/> + + + +We have downloaded a required software update. +Version [VERSION] + +We must restart [APP_NAME] to install the update. + + + + +We must restart [APP_NAME] to install the update. + setAppExitCallback(aecb); } +std::string LLUpdaterService::updatedVersion(void) +{ + return mImpl->updatedVersion(); +} + std::string const & ll_get_version(void) { static std::string version(""); diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 1ffa609019..421481bc43 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -90,6 +90,11 @@ public: app_exit_callback_t aecb = callable; setImplAppExitCallback(aecb); } + + // If an update is or has been downloaded, this method will return the + // version string for that update. An empty string will be returned + // otherwise. + std::string updatedVersion(void); private: boost::shared_ptr mImpl; -- cgit v1.3 From 4bab98f5cd2a815d10fe494a0a7e51cc237adb4a Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Fri, 10 Dec 2010 16:05:19 -0500 Subject: ESC-228 ESC-227 Corrections for metrics counters and send-on-quit delivery. Wanted to avoid computing metrics for duplicate requests as much as possible, they artificially depress averages but missed an opportunity and was including them in the counts. The non-texture case is solid. Textures are.... confounding still. Do a better job of trying to send one last packet to the grid when quitting. It is succeeding now, at least sometimes. Put a comment in base llassetstorage.cpp pointing to cut-n-paste derivation in llviewerassetstorage.cpp so that changes can be replicated. Hate doing this but current design forces it. --- indra/llmessage/llassetstorage.cpp | 4 ++++ indra/newview/llappviewer.cpp | 4 +++- indra/newview/llviewerassetstorage.cpp | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index b26d412e9f..27a368df3d 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -513,6 +513,10 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL } +// +// *NOTE: Logic here is replicated in LLViewerAssetStorage::_queueDataRequest. +// Changes here may need to be replicated in the viewer's derived class. +// void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype, LLGetAssetCallback callback, void *user_data, BOOL duplicate, diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 30005258ed..c667fba86f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3036,6 +3036,9 @@ void LLAppViewer::requestQuit() return; } + // Try to send metrics back to the grid + metricsSend(!gDisconnected); + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(gAgent.getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); @@ -3053,7 +3056,6 @@ void LLAppViewer::requestQuit() LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit")); send_stats(); - metricsSend(!gDisconnected); gLogoutTimer.reset(); mQuitRequested = true; diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 197cb3468c..36c8b42a52 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -348,7 +348,12 @@ void LLViewerAssetStorage::_queueDataRequest( req->mDownCallback = callback; req->mUserData = user_data; req->mIsPriority = is_priority; - req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + if (!duplicate) + { + // Only collect metrics for non-duplicate requests. Others + // are piggy-backing and will artificially lower averages. + req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); + } mPendingDownloads.push_back(req); -- cgit v1.3 From 11d420dd32e643a191c16b04f2fbb42c2b4db628 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Fri, 10 Dec 2010 17:41:05 -0800 Subject: Decided to refactor a bit. Was using LLSD as an internal data representation transferring ownership, doing data aggregation in a very pedantic way. That's just adding unneeded cost and complication. Used the same objects to transport data as are collecting it and everything got simpler, faster, easier to read with fewer gotchas. Bit myself *again* doing the min/max/mean merges but the unittests where there to pick me up again. Added a per-region FPS metric while I was at it. This is much asked for and there was a convenient place to sample the value. --- indra/newview/llappviewer.cpp | 31 +- indra/newview/llsimplestat.h | 18 + indra/newview/lltexturefetch.cpp | 98 ++-- indra/newview/lltexturefetch.h | 7 +- indra/newview/llviewerassetstats.cpp | 286 ++++-------- indra/newview/llviewerassetstats.h | 70 ++- indra/newview/tests/llsimplestat_test.cpp | 158 +++++++ indra/newview/tests/llviewerassetstats_test.cpp | 595 ++++++++++++++---------- 8 files changed, 740 insertions(+), 523 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c667fba86f..3640d01642 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3804,6 +3804,11 @@ void LLAppViewer::idle() llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl; gObjectList.mNumUnknownUpdates = 0; } + + // ViewerMetrics FPS piggy-backing on the debug timer. + // The 5-second interval is nice for this purpose. If the object debug + // bit moves or is disabled, please give this a suitable home. + LLViewerAssetStatsFF::record_fps_main(frame_rate_clamped); } } @@ -4805,23 +4810,17 @@ void LLAppViewer::metricsSend(bool enable_reporting) { std::string caps_url = regionp->getCapability("ViewerMetrics"); - // *NOTE: Pay attention here. LLSD's are not safe for thread sharing - // and their ownership is difficult to transfer across threads. We do - // it here by having only one reference (the new'd pointer) to the LLSD - // or any subtree of it. This pointer is then transfered to the other - // thread using correct thread logic to do all data ordering. - LLSD * envelope = new LLSD(LLSD::emptyMap()); - { - (*envelope) = gViewerAssetStatsMain->asLLSD(); - (*envelope)["session_id"] = gAgentSessionID; - (*envelope)["agent_id"] = gAgentID; - } - + // Make a copy of the main stats to send into another thread. + // Receiving thread takes ownership. + LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain)); + // Send a report request into 'thread1' to get the rest of the data - // and have it sent to the stats collector. LLSD ownership transfers - // with this call. - LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, envelope); - envelope = 0; // transfer noted + // and provide some additional parameters while here. + LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, + gAgentSessionID, + gAgentID, + main_stats); + main_stats = 0; // Ownership transferred } else { diff --git a/indra/newview/llsimplestat.h b/indra/newview/llsimplestat.h index f8f4be0390..a90e503adb 100644 --- a/indra/newview/llsimplestat.h +++ b/indra/newview/llsimplestat.h @@ -62,6 +62,9 @@ public: inline void reset() { mCount = 0; } + inline void merge(const LLSimpleStatCounter & src) + { mCount += src.mCount; } + inline U32 operator++() { return ++mCount; } inline U32 getCount() const { return mCount; } @@ -125,6 +128,21 @@ public: ++mCount; } + void merge(const LLSimpleStatMMM & src) + { + if (! mCount) + { + *this = src; + } + else if (src.mCount) + { + mMin = llmin(mMin, src.mMin); + mMax = llmax(mMax, src.mMax); + mCount += src.mCount; + mTotal += src.mTotal; + } + } + inline U32 getCount() const { return mCount; } inline Value getMin() const { return mMin; } inline Value getMax() const { return mMax; } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 73d78c9334..e1f9d7bdcc 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -442,18 +442,18 @@ namespace * | | TE | . +-------+ * | +--+--+ . | Thd1 | * | | . | | - * | (llsd) +-----+ . | Stats | + * | +-----+ . | Stats | * `--------->| RSC | . | | * +--+--+ . | Coll. | * | . +-------+ * +--+--+ . | * | SME |---. . | * +-----+ \ . | - * . \ (llsd) +-----+ | + * . \ (clone) +-----+ | * . `-------->| SM | | * . +--+--+ | * . | | - * . +-----+ (llsd) | + * . +-----+ | * . | RSC |<--------' * . +-----+ * . | @@ -472,11 +472,12 @@ namespace * SR - Set Region. New region UUID is sent to the thread-local * collector. * SME - Send Metrics Enqueued. Enqueue a 'Send Metrics' command - * including an ownership transfer of an LLSD. + * including an ownership transfer of a cloned LLViewerAssetStats. * TFReqSendMetrics carries the data. * SM - Send Metrics. Global metrics reporting operation. Takes - * the remote LLSD from the command, merges it with and LLSD - * from the local collector and sends it to the grid. + * the cloned stats from the command, merges it with the + * thread's local stats, converts to LLSD and sends it on + * to the grid. * AM - Agent Moved. Agent has completed some sort of move to a * new region. * TE - Timer Expired. Metrics timer has expired (on the order @@ -485,7 +486,8 @@ namespace * MSC - Modify Stats Collector. State change in the thread-local * collector. Typically a region change which affects the * global pointers used to find the 'current stats'. - * RSC - Read Stats Collector. Extract collector data in LLSD form. + * RSC - Read Stats Collector. Extract collector data cloning it + * (i.e. deep copy) when necessary. * */ class TFRequest // : public LLQueuedThread::QueuedRequest @@ -539,11 +541,12 @@ public: * * This is the big operation. The main thread gathers metrics * for a period of minutes into LLViewerAssetStats and other - * objects then builds an LLSD to represent the data. It uses - * this command to transfer the LLSD, content *and* ownership, - * to the TextureFetch thread which adds its own metrics and - * kicks of an HTTP POST of the resulting data to the currently - * active metrics collector. + * objects then makes a snapshot of the data by cloning the + * collector. This command transfers the clone, along with a few + * additional arguments (UUIDs), handing ownership to the + * TextureFetch thread. It then merges its own data into the + * cloned copy, converts to LLSD and kicks off an HTTP POST of + * the resulting data to the currently active metrics collector. * * Corresponds to LLTextureFetch::commandSendMetrics() */ @@ -558,16 +561,24 @@ public: * to receive the data. Does not have to * be associated with a particular region. * - * @param report_main Pointer to LLSD containing main - * thread metrics. Ownership transfers - * to the new thread using very carefully - * constructed code. + * @param session_id UUID of the agent's session. + * + * @param agent_id UUID of the agent. (Being pure here...) + * + * @param main_stats Pointer to a clone of the main thread's + * LLViewerAssetStats data. Thread1 takes + * ownership of the copy and disposes of it + * when done. */ TFReqSendMetrics(const std::string & caps_url, - LLSD * report_main) + const LLUUID & session_id, + const LLUUID & agent_id, + LLViewerAssetStats * main_stats) : TFRequest(), mCapsURL(caps_url), - mReportMain(report_main) + mSessionID(session_id), + mAgentID(agent_id), + mMainStats(main_stats) {} TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined @@ -577,7 +588,9 @@ public: public: const std::string mCapsURL; - LLSD * mReportMain; + const LLUUID mSessionID; + const LLUUID mAgentID; + LLViewerAssetStats * mMainStats; }; /* @@ -2727,9 +2740,11 @@ void LLTextureFetch::commandSetRegion(U64 region_handle) } void LLTextureFetch::commandSendMetrics(const std::string & caps_url, - LLSD * report_main) + const LLUUID & session_id, + const LLUUID & agent_id, + LLViewerAssetStats * main_stats) { - TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, report_main); + TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats); cmdEnqueue(req); } @@ -2808,14 +2823,14 @@ TFReqSetRegion::doWork(LLTextureFetch *) TFReqSendMetrics::~TFReqSendMetrics() { - delete mReportMain; - mReportMain = 0; + delete mMainStats; + mMainStats = 0; } /** * Implements the 'Send Metrics' command. Takes over - * ownership of the passed LLSD pointer. + * ownership of the passed LLViewerAssetStats pointer. * * Thread: Thread1 (TextureFetch) */ @@ -2893,33 +2908,36 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) static volatile bool reporting_started(false); static volatile S32 report_sequence(0); - // We've already taken over ownership of the LLSD at this point - // and can do normal LLSD sharing operations at this point. But - // still being careful, regardless. - LLSD & main_stats = *mReportMain; - - LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD(); // 'duration' & 'regions' from this LLSD - thread1_stats["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics - thread1_stats["sequence"] = report_sequence; // Sequence number - thread1_stats["initial"] = ! reporting_started; // Initial data from viewer - thread1_stats["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report + // We've taken over ownership of the stats copy at this + // point. Get a working reference to it for merging here + // but leave it in 'this'. Destructor will rid us of it. + LLViewerAssetStats & main_stats = *mMainStats; + + // Merge existing stats into those from main, convert to LLSD + main_stats.merge(*gViewerAssetStatsThread1); + LLSD merged_llsd = main_stats.asLLSD(); + + // Add some additional meta fields to the content + merged_llsd["session_id"] = mSessionID; + merged_llsd["agent_id"] = mAgentID; + merged_llsd["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics + merged_llsd["sequence"] = report_sequence; // Sequence number + merged_llsd["initial"] = ! reporting_started; // Initial data from viewer + merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report // Update sequence number if (S32_MAX == ++report_sequence) report_sequence = 0; - // Merge the two LLSDs into a single report - LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats); - // Limit the size of the stats report if necessary. - thread1_stats["truncated"] = truncate_viewer_metrics(10, thread1_stats); + merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd); if (! mCapsURL.empty()) { LLCurlRequest::headers_t headers; fetcher->getCurlRequest().post(mCapsURL, headers, - thread1_stats, + merged_llsd, new lcl_responder(report_sequence, report_sequence, LLTextureFetch::svMetricsDataBreak, @@ -2933,7 +2951,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) // In QA mode, Metrics submode, log the result for ease of testing if (fetcher->isQAMode()) { - LL_INFOS("Textures") << thread1_stats << LL_ENDL; + LL_INFOS("Textures") << merged_llsd << LL_ENDL; } gViewerAssetStatsThread1->reset(); diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index af30d1bb3b..a8fd3ce244 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -40,6 +40,8 @@ class HTTPGetResponder; class LLTextureCache; class LLImageDecodeThread; class LLHost; +class LLViewerAssetStats; + namespace { class TFRequest; } // Interface class @@ -88,7 +90,10 @@ public: // Commands available to other threads to control metrics gathering operations. void commandSetRegion(U64 region_handle); - void commandSendMetrics(const std::string & caps_url, LLSD * report_main); + void commandSendMetrics(const std::string & caps_url, + const LLUUID & session_id, + const LLUUID & agent_id, + LLViewerAssetStats * main_stats); void commandDataBreak(); LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; } diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index d798786277..399d62d2fc 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -113,11 +113,34 @@ LLViewerAssetStats::PerRegionStats::reset() mRequests[i].mDequeued.reset(); mRequests[i].mResponse.reset(); } - + mFPS.reset(); + mTotalTime = 0; mStartTimestamp = LLViewerAssetStatsFF::get_timestamp(); } + +void +LLViewerAssetStats::PerRegionStats::merge(const LLViewerAssetStats::PerRegionStats & src) +{ + // mRegionHandle, mTotalTime, mStartTimestamp are left alone. + + // mFPS + if (src.mFPS.getCount() && mFPS.getCount()) + { + mFPS.merge(src.mFPS); + } + + // Requests + for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i) + { + mRequests[i].mEnqueued.merge(src.mRequests[i].mEnqueued); + mRequests[i].mDequeued.merge(src.mRequests[i].mDequeued); + mRequests[i].mResponse.merge(src.mRequests[i].mResponse); + } +} + + void LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now) { @@ -136,6 +159,19 @@ LLViewerAssetStats::LLViewerAssetStats() } +LLViewerAssetStats::LLViewerAssetStats(const LLViewerAssetStats & src) + : mRegionHandle(src.mRegionHandle), + mResetTimestamp(src.mResetTimestamp) +{ + const PerRegionContainer::const_iterator it_end(src.mRegionStats.end()); + for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it) + { + mRegionStats[it->first] = new PerRegionStats(*it->second); + } + mCurRegionStats = mRegionStats[mRegionHandle]; +} + + void LLViewerAssetStats::reset() { @@ -215,6 +251,12 @@ LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_htt mCurRegionStats->mRequests[int(eac)].mResponse.record(duration); } +void +LLViewerAssetStats::recordFPS(F32 fps) +{ + mCurRegionStats->mFPS.record(fps); +} + LLSD LLViewerAssetStats::asLLSD() { @@ -231,7 +273,7 @@ LLViewerAssetStats::asLLSD() LLSD::String("get_other") }; - // Sub-tags. If you add or delete from this list, mergeRegionsLLSD() must be updated. + // Stats Group Sub-tags. static const LLSD::String enq_tag("enqueued"); static const LLSD::String deq_tag("dequeued"); static const LLSD::String rcnt_tag("resp_count"); @@ -239,6 +281,12 @@ LLViewerAssetStats::asLLSD() static const LLSD::String rmax_tag("resp_max"); static const LLSD::String rmean_tag("resp_mean"); + // MMM Group Sub-tags. + static const LLSD::String cnt_tag("count"); + static const LLSD::String min_tag("min"); + static const LLSD::String max_tag("max"); + static const LLSD::String mean_tag("mean"); + const duration_t now = LLViewerAssetStatsFF::get_timestamp(); mCurRegionStats->accumulateTime(now); @@ -257,7 +305,7 @@ LLViewerAssetStats::asLLSD() LLSD reg_stat = LLSD::emptyMap(); - for (int i = 0; i < EVACCount; ++i) + for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i) { LLSD & slot = reg_stat[tags[i]]; slot = LLSD::emptyMap(); @@ -269,6 +317,15 @@ LLViewerAssetStats::asLLSD() slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6)); } + { + LLSD & slot = reg_stat["fps"]; + slot = LLSD::emptyMap(); + slot[cnt_tag] = LLSD(S32(stats.mFPS.getCount())); + slot[min_tag] = LLSD(F64(stats.mFPS.getMin())); + slot[max_tag] = LLSD(F64(stats.mFPS.getMax())); + slot[mean_tag] = LLSD(F64(stats.mFPS.getMean())); + } + reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6); std::stringstream reg_handle; reg_handle.width(16); @@ -284,181 +341,24 @@ LLViewerAssetStats::asLLSD() return ret; } -/* static */ void -LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst) +void +LLViewerAssetStats::merge(const LLViewerAssetStats & src) { - // Merge operator definitions - static const int MOP_ADD_INT(0); - static const int MOP_MIN_REAL(1); - static const int MOP_MAX_REAL(2); - static const int MOP_MEAN_REAL(3); // Requires a 'mMergeOpArg' to weight the input terms - - static const LLSD::String regions_key("regions"); - static const LLSD::String resp_count_key("resp_count"); - - static const struct - { - LLSD::String mName; - int mMergeOp; - } - key_list[] = - { - // Order is important below. We modify the data in-place and - // so operations like MOP_MEAN_REAL which need the "resp_count" - // value for weighting must be performed before "resp_count" - // is modified or the weight will be wrong. Key list is - // defined in asLLSD() and must track it. - - { "resp_mean", MOP_MEAN_REAL }, - { "enqueued", MOP_ADD_INT }, - { "dequeued", MOP_ADD_INT }, - { "resp_min", MOP_MIN_REAL }, - { "resp_max", MOP_MAX_REAL }, - { resp_count_key, MOP_ADD_INT } // Keep last - }; + // mRegionHandle, mCurRegionStats and mResetTimestamp are left untouched. + // Just merge the stats bodies - // Trivial checks - if (! src.has(regions_key)) + const PerRegionContainer::const_iterator it_end(src.mRegionStats.end()); + for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it) { - return; - } - - if (! dst.has(regions_key)) - { - dst[regions_key] = src[regions_key]; - return; - } - - // Non-trivial cases requiring a deep merge. - const LLSD & root_src(src[regions_key]); - LLSD & root_dst(dst[regions_key]); - - const LLSD::map_const_iterator it_uuid_end(root_src.endMap()); - for (LLSD::map_const_iterator it_uuid(root_src.beginMap()); it_uuid_end != it_uuid; ++it_uuid) - { - if (! root_dst.has(it_uuid->first)) + PerRegionContainer::iterator dst(mRegionStats.find(it->first)); + if (mRegionStats.end() == dst) { - // src[] without matching dst[] - root_dst[it_uuid->first] = it_uuid->second; + // Destination is missing data, just make a private copy + mRegionStats[it->first] = new PerRegionStats(*it->second); } else { - // src[] with matching dst[] - // We have matching source and destination regions. - // Now iterate over each asset bin in the region status. Could iterate over - // an explicit list but this will do as well. - LLSD & reg_dst(root_dst[it_uuid->first]); - const LLSD & reg_src(root_src[it_uuid->first]); - - const LLSD::map_const_iterator it_sets_end(reg_src.endMap()); - for (LLSD::map_const_iterator it_sets(reg_src.beginMap()); it_sets_end != it_sets; ++it_sets) - { - static const LLSD::String no_touch_1("duration"); - - if (no_touch_1 == it_sets->first) - { - continue; - } - else if (! reg_dst.has(it_sets->first)) - { - // src[][] without matching dst[][] - reg_dst[it_sets->first] = it_sets->second; - } - else - { - // src[][] with matching dst[][] - // Matching stats bin in both source and destination regions. - // Iterate over those bin keys we know how to merge, leave the remainder untouched. - LLSD & bin_dst(reg_dst[it_sets->first]); - const LLSD & bin_src(reg_src[it_sets->first]); - - // The "resp_count" value is needed repeatedly in operations. - const LLSD::Integer bin_src_count(bin_src[resp_count_key].asInteger()); - const LLSD::Integer bin_dst_count(bin_dst[resp_count_key].asInteger()); - - for (int key_index(0); key_index < LL_ARRAY_SIZE(key_list); ++key_index) - { - const LLSD::String & key_name(key_list[key_index].mName); - - if (! bin_src.has(key_name)) - { - // Missing src[][][] - continue; - } - - const LLSD & src_value(bin_src[key_name]); - - if (! bin_dst.has(key_name)) - { - // src[][][] without matching dst[][][] - bin_dst[key_name] = src_value; - } - else - { - // src[][][] with matching dst[][][] - LLSD & dst_value(bin_dst[key_name]); - - switch (key_list[key_index].mMergeOp) - { - case MOP_ADD_INT: - // Simple counts, just add - dst_value = dst_value.asInteger() + src_value.asInteger(); - break; - - case MOP_MIN_REAL: - // Minimum - if (bin_src_count) - { - // If src has non-zero count, it's min is meaningful - if (bin_dst_count) - { - dst_value = llmin(dst_value.asReal(), src_value.asReal()); - } - else - { - dst_value = src_value; - } - } - break; - - case MOP_MAX_REAL: - // Maximum - if (bin_src_count) - { - // If src has non-zero count, it's max is meaningful - if (bin_dst_count) - { - dst_value = llmax(dst_value.asReal(), src_value.asReal()); - } - else - { - dst_value = src_value; - } - } - break; - - case MOP_MEAN_REAL: - { - // Mean - F64 src_weight(bin_src_count); - F64 dst_weight(bin_dst_count); - F64 tot_weight(src_weight + dst_weight); - if (tot_weight >= F64(0.5)) - { - dst_value = (((dst_value.asReal() * dst_weight) - + (src_value.asReal() * src_weight)) - / tot_weight); - } - } - break; - - default: - break; - } - } - } - } - } + dst->second->merge(*it->second); } } } @@ -526,6 +426,15 @@ record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration); } +void +record_fps_main(F32 fps) +{ + if (! gViewerAssetStatsMain) + return; + + gViewerAssetStatsMain->recordFPS(fps); +} + // 'thread1' - should be for TextureFetch thread @@ -590,41 +499,6 @@ cleanup() } -void -merge_stats(const LLSD & src, LLSD & dst) -{ - static const LLSD::String regions_key("regions"); - - // Trivial cases first - if (! src.isMap()) - { - return; - } - - if (! dst.isMap()) - { - dst = src; - return; - } - - // Okay, both src and dst are maps at this point. - // Collector class know how to merge the regions part. - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - // Now merge non-regions bits manually. - const LLSD::map_const_iterator it_end(src.endMap()); - for (LLSD::map_const_iterator it(src.beginMap()); it_end != it; ++it) - { - if (regions_key == it->first) - continue; - - if (dst.has(it->first)) - continue; - - dst[it->first] = it->second; - } -} - } // namespace LLViewerAssetStatsFF diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index ed2d0f3922..af6bf5b695 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -125,29 +125,48 @@ public: { reset(); } + + PerRegionStats(const PerRegionStats & src) + : LLRefCount(), + mRegionHandle(src.mRegionHandle), + mTotalTime(src.mTotalTime), + mStartTimestamp(src.mStartTimestamp), + mFPS(src.mFPS) + { + for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i) + { + mRequests[i] = src.mRequests[i]; + } + } + // Default assignment and destructor are correct. void reset(); + void merge(const PerRegionStats & src); + // Apply current running time to total and reset start point. // Return current timestamp as a convenience. void accumulateTime(duration_t now); public: - region_handle_t mRegionHandle; - duration_t mTotalTime; - duration_t mStartTimestamp; + region_handle_t mRegionHandle; + duration_t mTotalTime; + duration_t mStartTimestamp; + LLSimpleStatMMM<> mFPS; struct { LLSimpleStatCounter mEnqueued; LLSimpleStatCounter mDequeued; LLSimpleStatMMM mResponse; - } mRequests [EVACCount]; + } + mRequests [EVACCount]; }; public: LLViewerAssetStats(); + LLViewerAssetStats(const LLViewerAssetStats &); // Default destructor is correct. LLViewerAssetStats & operator=(const LLViewerAssetStats &); // Not defined @@ -165,6 +184,18 @@ public: void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp); void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration); + // Frames-Per-Second Samples + void recordFPS(F32 fps); + + // Merge a source instance into a destination instance. This is + // conceptually an 'operator+=()' method: + // - counts are added + // - minimums are min'd + // - maximums are max'd + // - other scalars are ignored ('this' wins) + // + void merge(const LLViewerAssetStats & src); + // Retrieve current metrics for all visited regions (NULL region UUID/handle excluded) // Returned LLSD is structured as follows: // @@ -177,11 +208,19 @@ public: // resp_mean : float // } // + // &mmm_group = { + // count : int, + // min : float, + // max : float, + // mean : float + // } + // // { // duration: int // regions: { // $: { // Keys are strings of the region's handle in hex // duration: : int, + // fps: : &mmm_group, // get_texture_temp_http : &stats_group, // get_texture_temp_udp : &stats_group, // get_texture_non_temp_http : &stats_group, @@ -195,15 +234,6 @@ public: // } LLSD asLLSD(); - // Merges the "regions" maps in two LLSDs structured as per asLLSD(). - // This takes two LLSDs as returned by asLLSD() and intelligently - // merges the metrics contained in the maps indexed by "regions". - // The remainder of the top-level map of the LLSDs is left unchanged - // in expectation that callers will add other information at this - // level. The "regions" information must be correctly formed or the - // final result is undefined (little defensive action). - static void mergeRegionsLLSD(const LLSD & src, LLSD & dst); - protected: typedef std::map > PerRegionContainer; @@ -278,6 +308,8 @@ void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_te void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration); +void record_fps_main(F32 fps); + /** * Region context, event and duration loggers for Thread 1. @@ -291,18 +323,6 @@ void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration); -/** - * @brief Merge two LLSD reports from different collector instances - * - * Use this to merge the LLSD's from two threads. For top-level, - * non-region data the destination (dst) is considered authoritative - * if the key is present in both source and destination. For - * regions, a numerical merge is performed when data are present in - * both source and destination and the 'right thing' is done for - * counts, minimums, maximums and averages. - */ -void merge_stats(const LLSD & src, LLSD & dst); - } // namespace LLViewerAssetStatsFF #endif // LL_LLVIEWERASSETSTATUS_H diff --git a/indra/newview/tests/llsimplestat_test.cpp b/indra/newview/tests/llsimplestat_test.cpp index 5efc9cf857..60a8cac995 100644 --- a/indra/newview/tests/llsimplestat_test.cpp +++ b/indra/newview/tests/llsimplestat_test.cpp @@ -425,4 +425,162 @@ namespace tut ensure("Overflowed MMM has huge max", (bignum == m1.getMax())); ensure("Overflowed MMM has fetchable mean", (zero == m1.getMean() || true)); } + + // Testing LLSimpleStatCounter's merge() method + template<> template<> + void stat_counter_index_object_t::test<12>() + { + LLSimpleStatCounter c1; + LLSimpleStatCounter c2; + + ++c1; + ++c1; + ++c1; + ++c1; + + ++c2; + ++c2; + c2.merge(c1); + + ensure_equals("4 merged into 2 results in 6", 6, c2.getCount()); + + ensure_equals("Source of merge is undamaged", 4, c1.getCount()); + } + + // Testing LLSimpleStatMMM's merge() method + template<> template<> + void stat_counter_index_object_t::test<13>() + { + LLSimpleStatMMM<> m1; + LLSimpleStatMMM<> m2; + + m1.record(3.5); + m1.record(4.5); + m1.record(5.5); + m1.record(6.5); + + m2.record(5.0); + m2.record(7.0); + m2.record(9.0); + + m2.merge(m1); + + ensure_equals("Count after merge (p1)", 7, m2.getCount()); + ensure_approximately_equals("Min after merge (p1)", F32(3.5), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p1)", F32(41.000/7.000), m2.getMean(), 22); + + + ensure_equals("Source count of merge is undamaged (p1)", 4, m1.getCount()); + ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(3.5), m1.getMin(), 22); + ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(6.5), m1.getMax(), 22); + ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(5.0), m1.getMean(), 22); + + m2.reset(); + + m2.record(-22.0); + m2.record(-1.0); + m2.record(30.0); + + m2.merge(m1); + + ensure_equals("Count after merge (p2)", 7, m2.getCount()); + ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p2)", F32(30.0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p2)", F32(27.000/7.000), m2.getMean(), 22); + + } + + // Testing LLSimpleStatMMM's merge() method when src contributes nothing + template<> template<> + void stat_counter_index_object_t::test<14>() + { + LLSimpleStatMMM<> m1; + LLSimpleStatMMM<> m2; + + m2.record(5.0); + m2.record(7.0); + m2.record(9.0); + + m2.merge(m1); + + ensure_equals("Count after merge (p1)", 3, m2.getCount()); + ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22); + + ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount()); + ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22); + ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22); + ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22); + + m2.reset(); + + m2.record(-22.0); + m2.record(-1.0); + + m2.merge(m1); + + ensure_equals("Count after merge (p2)", 2, m2.getCount()); + ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22); + } + + // Testing LLSimpleStatMMM's merge() method when dst contributes nothing + template<> template<> + void stat_counter_index_object_t::test<15>() + { + LLSimpleStatMMM<> m1; + LLSimpleStatMMM<> m2; + + m1.record(5.0); + m1.record(7.0); + m1.record(9.0); + + m2.merge(m1); + + ensure_equals("Count after merge (p1)", 3, m2.getCount()); + ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22); + + ensure_equals("Source count of merge is undamaged (p1)", 3, m1.getCount()); + ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(5.0), m1.getMin(), 22); + ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(9.0), m1.getMax(), 22); + ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(7.0), m1.getMean(), 22); + + m1.reset(); + m2.reset(); + + m1.record(-22.0); + m1.record(-1.0); + + m2.merge(m1); + + ensure_equals("Count after merge (p2)", 2, m2.getCount()); + ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22); + } + + // Testing LLSimpleStatMMM's merge() method when neither dst nor src contributes + template<> template<> + void stat_counter_index_object_t::test<16>() + { + LLSimpleStatMMM<> m1; + LLSimpleStatMMM<> m2; + + m2.merge(m1); + + ensure_equals("Count after merge (p1)", 0, m2.getCount()); + ensure_approximately_equals("Min after merge (p1)", F32(0), m2.getMin(), 22); + ensure_approximately_equals("Max after merge (p1)", F32(0), m2.getMax(), 22); + ensure_approximately_equals("Mean after merge (p1)", F32(0), m2.getMean(), 22); + + ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount()); + ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22); + ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22); + ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22); + } } diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 153056b3cd..9c54266017 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -44,6 +44,7 @@ static const char * all_keys[] = { "duration", + "fps", "get_other", "get_texture_temp_http", "get_texture_temp_udp", @@ -76,6 +77,19 @@ static const char * sub_keys[] = "resp_mean" }; +static const char * mmm_resp_keys[] = +{ + "fps" +}; + +static const char * mmm_sub_keys[] = +{ + "count", + "max", + "min", + "mean" +}; + static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8"); static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a"); static const U64 region1_handle(0x00000401000003f7ULL); @@ -172,6 +186,15 @@ namespace tut ensure(line, sd[resp_keys[i]].has(sub_keys[j])); } } + + for (int i = 0; i < LL_ARRAY_SIZE(mmm_resp_keys); ++i) + { + for (int j = 0; j < LL_ARRAY_SIZE(mmm_sub_keys); ++j) + { + std::string line = llformat("Key '%s' has '%s' key", mmm_resp_keys[i], mmm_sub_keys[j]); + ensure(line, sd[mmm_resp_keys[i]].has(mmm_sub_keys[j])); + } + } } // Create a non-global instance and check some content @@ -461,293 +484,395 @@ namespace tut ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); } - // Check that the LLSD merger knows what it's doing (basic test) + + // LLViewerAssetStats::merge() basic functions work template<> template<> void tst_viewerassetstats_index_object_t::test<9>() { - LLSD::String reg1_name = region1_handle_str; - LLSD::String reg2_name = region2_handle_str; - - LLSD reg1_stats = LLSD::emptyMap(); - LLSD reg2_stats = LLSD::emptyMap(); - - LLSD & tmp_other1 = reg1_stats["get_other"]; - tmp_other1["enqueued"] = 4; - tmp_other1["dequeued"] = 4; - tmp_other1["resp_count"] = 8; - tmp_other1["resp_max"] = F64(23.2892); - tmp_other1["resp_min"] = F64(0.2829); - tmp_other1["resp_mean"] = F64(2.298928); - - LLSD & tmp_other2 = reg2_stats["get_other"]; - tmp_other2["enqueued"] = 8; - tmp_other2["dequeued"] = 7; - tmp_other2["resp_count"] = 3; - tmp_other2["resp_max"] = F64(6.5); - tmp_other2["resp_min"] = F64(0.01); - tmp_other2["resp_mean"] = F64(4.1); + LLViewerAssetStats s1; + LLViewerAssetStats s2; + + s1.setRegion(region1_handle); + s2.setRegion(region1_handle); + + s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 5000000); + s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 6000000); + s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 8000000); + s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 7000000); + s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 9000000); - { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 2000000); + s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 3000000); + s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 4000000); - src["regions"][reg1_name] = reg1_stats; - src["duration"] = 24; - dst["regions"][reg2_name] = reg2_stats; - dst["duration"] = 36; + s2.merge(s1); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); + LLSD s2_llsd = s2.asLLSD(); - ensure("region 1 in merged stats", llsd_equals(reg1_stats, dst["regions"][reg1_name])); - ensure("region 2 still in merged stats", llsd_equals(reg2_stats, dst["regions"][reg2_name])); - } + ensure_equals("count after merge", 8, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_count"].asInteger()); + ensure_approximately_equals("min after merge", 2.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_min"].asReal(), 22); + ensure_approximately_equals("max after merge", 9.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_max"].asReal(), 22); + ensure_approximately_equals("max after merge", 5.5, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_mean"].asReal(), 22); - { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); - - src["regions"][reg1_name] = reg1_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg2_stats; - dst["duration"] = 36; - - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - ensure("src not ruined", llsd_equals(reg1_stats, src["regions"][reg1_name])); - ensure_equals("added enqueued counts", dst["regions"][reg1_name]["get_other"]["enqueued"].asInteger(), 12); - ensure_equals("added dequeued counts", dst["regions"][reg1_name]["get_other"]["dequeued"].asInteger(), 11); - ensure_equals("added response counts", dst["regions"][reg1_name]["get_other"]["resp_count"].asInteger(), 11); - ensure_approximately_equals("min'd minimum response times", dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), 0.01, 20); - ensure_approximately_equals("max'd maximum response times", dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), 23.2892, 20); - ensure_approximately_equals("weighted mean of means", dst["regions"][reg1_name]["get_other"]["resp_mean"].asReal(), 2.7901295, 20); - } } - // Maximum merges are interesting when one side contributes nothing + // LLViewerAssetStats::merge() basic functions work without corrupting source data template<> template<> void tst_viewerassetstats_index_object_t::test<10>() { - LLSD::String reg1_name = region1_handle_str; - LLSD::String reg2_name = region2_handle_str; - - LLSD reg1_stats = LLSD::emptyMap(); - LLSD reg2_stats = LLSD::emptyMap(); - - LLSD & tmp_other1 = reg1_stats["get_other"]; - tmp_other1["enqueued"] = 4; - tmp_other1["dequeued"] = 4; - tmp_other1["resp_count"] = 7; - tmp_other1["resp_max"] = F64(-23.2892); - tmp_other1["resp_min"] = F64(-123.2892); - tmp_other1["resp_mean"] = F64(-58.28298); - - LLSD & tmp_other2 = reg2_stats["get_other"]; - tmp_other2["enqueued"] = 8; - tmp_other2["dequeued"] = 7; - tmp_other2["resp_count"] = 0; - tmp_other2["resp_max"] = F64(0); - tmp_other2["resp_min"] = F64(0); - tmp_other2["resp_mean"] = F64(0); - - { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + LLViewerAssetStats s1; + LLViewerAssetStats s2; - src["regions"][reg1_name] = reg1_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg2_stats; - dst["duration"] = 36; + s1.setRegion(region1_handle); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum", - dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); - } - - { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); - src["regions"][reg1_name] = reg2_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg1_stats; - dst["duration"] = 36; + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - ensure_approximately_equals("src maximum with count 0 does not contribute to merged maximum", - dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); - } - } + s2.setRegion(region2_handle); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000); + s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000); - // Minimum merges are interesting when one side contributes nothing - template<> template<> - void tst_viewerassetstats_index_object_t::test<11>() - { - LLSD::String reg1_name = region1_handle_str; - LLSD::String reg2_name = region2_handle_str; - - LLSD reg1_stats = LLSD::emptyMap(); - LLSD reg2_stats = LLSD::emptyMap(); - - LLSD & tmp_other1 = reg1_stats["get_other"]; - tmp_other1["enqueued"] = 4; - tmp_other1["dequeued"] = 4; - tmp_other1["resp_count"] = 7; - tmp_other1["resp_max"] = F64(123.2892); - tmp_other1["resp_min"] = F64(23.2892); - tmp_other1["resp_mean"] = F64(58.28298); - - LLSD & tmp_other2 = reg2_stats["get_other"]; - tmp_other2["enqueued"] = 8; - tmp_other2["dequeued"] = 7; - tmp_other2["resp_count"] = 0; - tmp_other2["resp_max"] = F64(0); - tmp_other2["resp_min"] = F64(0); - tmp_other2["resp_mean"] = F64(0); - { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); - - src["regions"][reg1_name] = reg1_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg2_stats; - dst["duration"] = 36; + s2.merge(s1); + + LLSD src = s1.asLLSD(); + LLSD dst = s2.asLLSD(); + + // Remove time stamps, they're a problem + src.erase("duration"); + src["regions"][region1_handle_str].erase("duration"); + dst.erase("duration"); + dst["regions"][region1_handle_str].erase("duration"); + dst["regions"][region2_handle_str].erase("duration"); + + ensure_equals("merge src has single region", 1, src["regions"].size()); + ensure_equals("merge dst has dual regions", 2, dst["regions"].size()); + ensure("result from src is in dst", llsd_equals(src["regions"][region1_handle_str], + dst["regions"][region1_handle_str])); + } - LLViewerAssetStats::mergeRegionsLLSD(src, dst); + s1.setRegion(region1_handle); + s2.setRegion(region1_handle); + s1.reset(); + s2.reset(); - ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum", - dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); - } + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); - { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); - src["regions"][reg1_name] = reg2_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg1_stats; - dst["duration"] = 36; + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - ensure_approximately_equals("src minimum with count 0 does not contribute to merged minimum", - dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + s2.setRegion(region1_handle); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000); + s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000); + + { + s2.merge(s1); + + LLSD src = s1.asLLSD(); + LLSD dst = s2.asLLSD(); + + // Remove time stamps, they're a problem + src.erase("duration"); + src["regions"][region1_handle_str].erase("duration"); + dst.erase("duration"); + dst["regions"][region1_handle_str].erase("duration"); + + ensure_equals("src counts okay (enq)", 4, src["regions"][region1_handle_str]["get_other"]["enqueued"].asInteger()); + ensure_equals("src counts okay (deq)", 4, src["regions"][region1_handle_str]["get_other"]["dequeued"].asInteger()); + ensure_equals("src resp counts okay", 2, src["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger()); + ensure_approximately_equals("src respmin okay", 0.2829, src["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), 20); + ensure_approximately_equals("src respmax okay", 23.2892, src["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), 20); + + ensure_equals("dst counts okay (enq)", 12, dst["regions"][region1_handle_str]["get_other"]["enqueued"].asInteger()); + ensure_equals("src counts okay (deq)", 11, dst["regions"][region1_handle_str]["get_other"]["dequeued"].asInteger()); + ensure_equals("dst resp counts okay", 4, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger()); + ensure_approximately_equals("dst respmin okay", 0.010, dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), 20); + ensure_approximately_equals("dst respmax okay", 23.2892, dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), 20); } } - // resp_count missing is taken as '0' for maximum calculation + + // Maximum merges are interesting when one side contributes nothing template<> template<> - void tst_viewerassetstats_index_object_t::test<12>() + void tst_viewerassetstats_index_object_t::test<11>() { - LLSD::String reg1_name = region1_handle_str; - LLSD::String reg2_name = region2_handle_str; - - LLSD reg1_stats = LLSD::emptyMap(); - LLSD reg2_stats = LLSD::emptyMap(); - - LLSD & tmp_other1 = reg1_stats["get_other"]; - tmp_other1["enqueued"] = 4; - tmp_other1["dequeued"] = 4; - tmp_other1["resp_count"] = 7; - tmp_other1["resp_max"] = F64(-23.2892); - tmp_other1["resp_min"] = F64(-123.2892); - tmp_other1["resp_mean"] = F64(-58.28298); - - LLSD & tmp_other2 = reg2_stats["get_other"]; - tmp_other2["enqueued"] = 8; - tmp_other2["dequeued"] = 7; - // tmp_other2["resp_count"] = 0; - tmp_other2["resp_max"] = F64(0); - tmp_other2["resp_min"] = F64(0); - tmp_other2["resp_mean"] = F64(0); - + LLViewerAssetStats s1; + LLViewerAssetStats s2; + + s1.setRegion(region1_handle); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + // Want to test negative numbers here but have to work in U64 + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + + s2.setRegion(region1_handle); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s2.merge(s1); + + LLSD src = s1.asLLSD(); + LLSD dst = s2.asLLSD(); - src["regions"][reg1_name] = reg1_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg2_stats; - dst["duration"] = 36; + // Remove time stamps, they're a problem + src.erase("duration"); + src["regions"][region1_handle_str].erase("duration"); + dst.erase("duration"); + dst["regions"][region1_handle_str].erase("duration"); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - ensure_approximately_equals("dst maximum with undefined count does not contribute to merged maximum", - dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); + ensure_equals("dst counts come from src only", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger()); + + ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum", + dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), F64(0.0), 20); } + // Other way around + s1.setRegion(region1_handle); + s2.setRegion(region1_handle); + s1.reset(); + s2.reset(); + + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + // Want to test negative numbers here but have to work in U64 + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s1.merge(s2); + + LLSD src = s2.asLLSD(); + LLSD dst = s1.asLLSD(); - src["regions"][reg1_name] = reg2_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg1_stats; - dst["duration"] = 36; + // Remove time stamps, they're a problem + src.erase("duration"); + src["regions"][region1_handle_str].erase("duration"); + dst.erase("duration"); + dst["regions"][region1_handle_str].erase("duration"); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - ensure_approximately_equals("src maximum with undefined count does not contribute to merged maximum", - dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); + ensure_equals("dst counts come from src only (flipped)", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger()); + + ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum (flipped)", + dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), F64(0.0), 20); } } - // resp_count unspecified is taken as 0 for minimum merges + // Minimum merges are interesting when one side contributes nothing template<> template<> - void tst_viewerassetstats_index_object_t::test<13>() + void tst_viewerassetstats_index_object_t::test<12>() { - LLSD::String reg1_name = region1.asString(); - LLSD::String reg2_name = region2.asString(); - - LLSD reg1_stats = LLSD::emptyMap(); - LLSD reg2_stats = LLSD::emptyMap(); - - LLSD & tmp_other1 = reg1_stats["get_other"]; - tmp_other1["enqueued"] = 4; - tmp_other1["dequeued"] = 4; - tmp_other1["resp_count"] = 7; - tmp_other1["resp_max"] = F64(123.2892); - tmp_other1["resp_min"] = F64(23.2892); - tmp_other1["resp_mean"] = F64(58.28298); - - LLSD & tmp_other2 = reg2_stats["get_other"]; - tmp_other2["enqueued"] = 8; - tmp_other2["dequeued"] = 7; - // tmp_other2["resp_count"] = 0; - tmp_other2["resp_max"] = F64(0); - tmp_other2["resp_min"] = F64(0); - tmp_other2["resp_mean"] = F64(0); - + LLViewerAssetStats s1; + LLViewerAssetStats s2; + + s1.setRegion(region1_handle); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000); + + s2.setRegion(region1_handle); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s2.merge(s1); + + LLSD src = s1.asLLSD(); + LLSD dst = s2.asLLSD(); - src["regions"][reg1_name] = reg1_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg2_stats; - dst["duration"] = 36; + // Remove time stamps, they're a problem + src.erase("duration"); + src["regions"][region1_handle_str].erase("duration"); + dst.erase("duration"); + dst["regions"][region1_handle_str].erase("duration"); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - ensure_approximately_equals("dst minimum with undefined count does not contribute to merged minimum", - dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + ensure_equals("dst counts come from src only", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger()); + + ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum", + dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), F64(2.7), 20); } + // Other way around + s1.setRegion(region1_handle); + s2.setRegion(region1_handle); + s1.reset(); + s2.reset(); + + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000); + s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000); + + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + { - LLSD src = LLSD::emptyMap(); - LLSD dst = LLSD::emptyMap(); + s1.merge(s2); + + LLSD src = s2.asLLSD(); + LLSD dst = s1.asLLSD(); - src["regions"][reg1_name] = reg2_stats; - src["duration"] = 24; - dst["regions"][reg1_name] = reg1_stats; - dst["duration"] = 36; + // Remove time stamps, they're a problem + src.erase("duration"); + src["regions"][region1_handle_str].erase("duration"); + dst.erase("duration"); + dst["regions"][region1_handle_str].erase("duration"); - LLViewerAssetStats::mergeRegionsLLSD(src, dst); - - ensure_approximately_equals("src minimum with undefined count does not contribute to merged minimum", - dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + ensure_equals("dst counts come from src only (flipped)", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger()); + + ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum (flipped)", + dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), F64(2.7), 20); } } + } -- cgit v1.3 From e58965255d1edcb44256e1b27d813167df746034 Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Fri, 10 Dec 2010 18:31:38 -0800 Subject: CHOP-260 implementation. Update Ready notification gets real UI. reviewed by Mani. --- indra/newview/llappviewer.cpp | 78 +++++++++++++--------- .../newview/skins/default/xui/en/notifications.xml | 12 ++-- 2 files changed, 53 insertions(+), 37 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5bd0a0d297..eb8d87e184 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2417,55 +2417,71 @@ namespace { LLUpdaterService().startChecking(install_if_ready); } - void on_required_update_downloaded(LLSD const & data) + void on_update_downloaded(LLSD const & data) { std::string notification_name; - if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) + void (*apply_callback)(LLSD const &, LLSD const &) = NULL; + + if(data["required"].asBoolean()) { - // The user never saw the progress bar. - notification_name = "RequiredUpdateDownloadedVerboseDialog"; + apply_callback = &apply_update_ok_callback; + if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) + { + // The user never saw the progress bar. + notification_name = "RequiredUpdateDownloadedVerboseDialog"; + } + else + { + notification_name = "RequiredUpdateDownloadedDialog"; + } } else { - notification_name = "RequiredUpdateDownloadedDialog"; + apply_callback = &apply_update_callback; + if(LLStartUp::getStartupState() < STATE_STARTED) + { + // CHOP-262 we need to use a different notification + // method prior to login. + notification_name = "DownloadBackgroundDialog"; + } + else + { + notification_name = "DownloadBackgroundTip"; + } } + LLSD substitutions; substitutions["VERSION"] = data["version"]; - LLNotificationsUtil::add(notification_name, substitutions, LLSD(), &apply_update_ok_callback); - } - - void on_optional_update_downloaded(LLSD const & data) - { - std::string notification_name; - if(LLStartUp::getStartupState() < STATE_STARTED) - { - // CHOP-262 we need to use a different notification - // method prior to login. - notification_name = "DownloadBackgroundDialog"; - } - else + + // truncate version at the rightmost '.' + std::string version_short(data["version"]); + size_t short_length = version_short.rfind('.'); + if (short_length != std::string::npos) { - notification_name = "DownloadBackgroundTip"; + version_short.resize(short_length); } - LLSD substitutions; - substitutions["VERSION"] = data["version"]; - LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_update_callback); - } + LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]"); + relnotes_url.setArg("[VERSION_SHORT]", version_short); + + // *TODO thread the update service's response through to this point + std::string const & channel = LLVersionInfo::getChannel(); + boost::shared_ptr channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free); + + relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get()); + relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL")); + substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString(); + + LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback); + } + bool notify_update(LLSD const & evt) { std::string notification_name; switch (evt["type"].asInteger()) { case LLUpdaterService::DOWNLOAD_COMPLETE: - if(evt["required"].asBoolean()) - { - on_required_update_downloaded(evt); - } - else - { - on_optional_update_downloaded(evt); - } + on_update_downloaded(evt); break; case LLUpdaterService::INSTALL_ERROR: LLNotificationsUtil::add("FailedUpdateInstall"); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index eecbeeb8dc..b0bb93c13a 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2906,20 +2906,20 @@ or you can install it now. icon="notify.tga" name="DownloadBackgroundTip" type="notify"> -We have downloaded and update to your [APP_NAME] installation. -Version [VERSION] +We have downloaded an update to your [APP_NAME] installation. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update] + notext="Later..." + yestext="Install now and restart [APP_NAME]"/> -We have downloaded and update to your [APP_NAME] installation. -Version [VERSION] +We have downloaded an update to your [APP_NAME] installation. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update] Date: Sat, 11 Dec 2010 16:16:07 -0500 Subject: ESC-211 ESC-212 Use arrays in payload to grid and compact payload First, introduced a compact payload format that allows blocks of metrics to be dropped from the viewer->collector payload compressing 1200 bytes of LLSD into about 300, give-or-take. Then converted to using LLSD arrays in the payload to enumerate the regions encountered. This simplifies much data handling from the viewer all the way into the final formatter of the metrics on the grid. --- indra/newview/llappviewer.cpp | 2 +- indra/newview/lltexturefetch.cpp | 2 +- indra/newview/llviewerassetstats.cpp | 42 ++++++++++++------- indra/newview/llviewerassetstats.h | 10 ++++- indra/newview/tests/llviewerassetstats_test.cpp | 56 ++++++++++++------------- 5 files changed, 64 insertions(+), 48 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3640d01642..32bd51d3e2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3808,7 +3808,7 @@ void LLAppViewer::idle() // ViewerMetrics FPS piggy-backing on the debug timer. // The 5-second interval is nice for this purpose. If the object debug // bit moves or is disabled, please give this a suitable home. - LLViewerAssetStatsFF::record_fps_main(frame_rate_clamped); + LLViewerAssetStatsFF::record_fps_main(gFPSClamped); } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index e1f9d7bdcc..88905372f6 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2915,7 +2915,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) // Merge existing stats into those from main, convert to LLSD main_stats.merge(*gViewerAssetStatsThread1); - LLSD merged_llsd = main_stats.asLLSD(); + LLSD merged_llsd = main_stats.asLLSD(true); // Add some additional meta fields to the content merged_llsd["session_id"] = mSessionID; diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index 399d62d2fc..5ad7725b3e 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "llviewerassetstats.h" +#include "llregionhandle.h" #include "stdtypes.h" @@ -258,7 +259,7 @@ LLViewerAssetStats::recordFPS(F32 fps) } LLSD -LLViewerAssetStats::asLLSD() +LLViewerAssetStats::asLLSD(bool compact_output) { // Top-level tags static const LLSD::String tags[EVACCount] = @@ -290,7 +291,7 @@ LLViewerAssetStats::asLLSD() const duration_t now = LLViewerAssetStatsFF::get_timestamp(); mCurRegionStats->accumulateTime(now); - LLSD regions = LLSD::emptyMap(); + LLSD regions = LLSD::emptyArray(); for (PerRegionContainer::iterator it = mRegionStats.begin(); mRegionStats.end() != it; ++it) @@ -307,16 +308,25 @@ LLViewerAssetStats::asLLSD() for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i) { - LLSD & slot = reg_stat[tags[i]]; - slot = LLSD::emptyMap(); - slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount())); - slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount())); - slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount())); - slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6)); - slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6)); - slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6)); + PerRegionStats::prs_group & group(stats.mRequests[i]); + + if ((! compact_output) || + group.mEnqueued.getCount() || + group.mDequeued.getCount() || + group.mResponse.getCount()) + { + LLSD & slot = reg_stat[tags[i]]; + slot = LLSD::emptyMap(); + slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount())); + slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount())); + slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount())); + slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6)); + slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6)); + slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6)); + } } + if ((! compact_output) || stats.mFPS.getCount()) { LLSD & slot = reg_stat["fps"]; slot = LLSD::emptyMap(); @@ -326,12 +336,12 @@ LLViewerAssetStats::asLLSD() slot[mean_tag] = LLSD(F64(stats.mFPS.getMean())); } - reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6); - std::stringstream reg_handle; - reg_handle.width(16); - reg_handle.fill('0'); - reg_handle << std::hex << it->first; - regions[reg_handle.str()] = reg_stat; + U32 grid_x(0), grid_y(0); + grid_from_region_handle(it->first, &grid_x, &grid_y); + reg_stat["grid_x"] = LLSD::Integer(grid_x); + reg_stat["grid_y"] = LLSD::Integer(grid_y); + reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6); + regions.append(reg_stat); } LLSD ret = LLSD::emptyMap(); diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index af6bf5b695..905ceefad5 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -155,7 +155,7 @@ public: duration_t mStartTimestamp; LLSimpleStatMMM<> mFPS; - struct + struct prs_group { LLSimpleStatCounter mEnqueued; LLSimpleStatCounter mDequeued; @@ -232,7 +232,13 @@ public: // } // } // } - LLSD asLLSD(); + // + // @param compact_output If true, omits from conversion any mmm_block + // or stats_block that would contain all zero data. + // Useful for transmission when the receiver knows + // what is expected and will assume zero for missing + // blocks. + LLSD asLLSD(bool compact_output); protected: typedef std::map > PerRegionContainer; diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 9c54266017..40a7103dba 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -155,7 +155,7 @@ namespace tut ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain)); - LLSD sd_full = it->asLLSD(); + LLSD sd_full = it->asLLSD(false); // Default (NULL) region ID doesn't produce LLSD results so should // get an empty map back from output @@ -163,7 +163,7 @@ namespace tut // Once the region is set, we will get a response even with no data collection it->setRegion(region1_handle); - sd_full = it->asLLSD(); + sd_full = it->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1_handle_str)); @@ -204,7 +204,7 @@ namespace tut LLViewerAssetStats * it = new LLViewerAssetStats(); it->setRegion(region1_handle); - LLSD sd = it->asLLSD(); + LLSD sd = it->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); sd = sd[region1_handle_str]; @@ -229,7 +229,7 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); - LLSD sd = gViewerAssetStatsMain->asLLSD(); + LLSD sd = gViewerAssetStatsMain->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); sd = sd["regions"][region1_handle_str]; @@ -244,7 +244,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; + sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -267,9 +267,9 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); - LLSD sd = gViewerAssetStatsThread1->asLLSD(); + LLSD sd = gViewerAssetStatsThread1->asLLSD(false); ensure("Other collector is empty", is_no_stats_map(sd)); - sd = gViewerAssetStatsMain->asLLSD(); + sd = gViewerAssetStatsMain->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); sd = sd["regions"][region1_handle_str]; @@ -284,7 +284,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; + sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -316,7 +316,7 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); - LLSD sd = gViewerAssetStatsMain->asLLSD(); + LLSD sd = gViewerAssetStatsMain->asLLSD(false); // std::cout << sd << std::endl; @@ -340,7 +340,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD(); + sd = gViewerAssetStatsMain->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str)); sd2 = sd["regions"][region2_handle_str]; @@ -388,7 +388,7 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); - LLSD sd = gViewerAssetStatsMain->asLLSD(); + LLSD sd = gViewerAssetStatsMain->asLLSD(false); ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str)); @@ -410,7 +410,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD(); + sd = gViewerAssetStatsMain->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str)); sd2 = sd["regions"][region2_handle_str]; @@ -453,9 +453,9 @@ namespace tut LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true); - LLSD sd = gViewerAssetStatsThread1->asLLSD(); + LLSD sd = gViewerAssetStatsThread1->asLLSD(false); ensure("Other collector is empty", is_no_stats_map(sd)); - sd = gViewerAssetStatsMain->asLLSD(); + sd = gViewerAssetStatsMain->asLLSD(false); ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); sd = sd["regions"][region1_handle_str]; @@ -473,7 +473,7 @@ namespace tut // Reset and check zeros... // Reset leaves current region in place gViewerAssetStatsMain->reset(); - sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; + sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str]; delete gViewerAssetStatsMain; gViewerAssetStatsMain = NULL; @@ -507,7 +507,7 @@ namespace tut s2.merge(s1); - LLSD s2_llsd = s2.asLLSD(); + LLSD s2_llsd = s2.asLLSD(false); ensure_equals("count after merge", 8, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_count"].asInteger()); ensure_approximately_equals("min after merge", 2.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_min"].asReal(), 22); @@ -562,8 +562,8 @@ namespace tut { s2.merge(s1); - LLSD src = s1.asLLSD(); - LLSD dst = s2.asLLSD(); + LLSD src = s1.asLLSD(false); + LLSD dst = s2.asLLSD(false); // Remove time stamps, they're a problem src.erase("duration"); @@ -621,8 +621,8 @@ namespace tut { s2.merge(s1); - LLSD src = s1.asLLSD(); - LLSD dst = s2.asLLSD(); + LLSD src = s1.asLLSD(false); + LLSD dst = s2.asLLSD(false); // Remove time stamps, they're a problem src.erase("duration"); @@ -689,8 +689,8 @@ namespace tut { s2.merge(s1); - LLSD src = s1.asLLSD(); - LLSD dst = s2.asLLSD(); + LLSD src = s1.asLLSD(false); + LLSD dst = s2.asLLSD(false); // Remove time stamps, they're a problem src.erase("duration"); @@ -745,8 +745,8 @@ namespace tut { s1.merge(s2); - LLSD src = s2.asLLSD(); - LLSD dst = s1.asLLSD(); + LLSD src = s2.asLLSD(false); + LLSD dst = s1.asLLSD(false); // Remove time stamps, they're a problem src.erase("duration"); @@ -804,8 +804,8 @@ namespace tut { s2.merge(s1); - LLSD src = s1.asLLSD(); - LLSD dst = s2.asLLSD(); + LLSD src = s1.asLLSD(false); + LLSD dst = s2.asLLSD(false); // Remove time stamps, they're a problem src.erase("duration"); @@ -859,8 +859,8 @@ namespace tut { s1.merge(s2); - LLSD src = s2.asLLSD(); - LLSD dst = s1.asLLSD(); + LLSD src = s2.asLLSD(false); + LLSD dst = s1.asLLSD(false); // Remove time stamps, they're a problem src.erase("duration"); -- cgit v1.3 From f4884faf3a020a718c611f34aa534e80d8a8b666 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 13 Dec 2010 12:33:19 -0800 Subject: Expanded viewer stats recorder to include cache miss type, cache miss requests, and update failures --- indra/newview/llappviewer.cpp | 11 +++ indra/newview/llviewerobjectlist.cpp | 26 +++--- indra/newview/llviewerregion.cpp | 14 ++- indra/newview/llviewerregion.h | 9 +- indra/newview/llviewerstatsrecorder.cpp | 150 ++++++++++++++++++++++---------- indra/newview/llviewerstatsrecorder.h | 44 +++++++--- 6 files changed, 173 insertions(+), 81 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6c07974f69..5972e7aef8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -44,6 +44,7 @@ #include "llagentwearables.h" #include "llwindow.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llmd5.h" #include "llpumpio.h" #include "llmimetypes.h" @@ -648,6 +649,10 @@ bool LLAppViewer::init() mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); +#if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::initClass(); +#endif + // *NOTE:Mani - LLCurl::initClass is not thread safe. // Called before threads are created. LLCurl::initClass(); @@ -950,6 +955,8 @@ bool LLAppViewer::init() LLAgentLanguage::init(); + + return true; } @@ -1665,6 +1672,10 @@ bool LLAppViewer::cleanup() } LLMetricPerformanceTesterBasic::cleanClass() ; +#if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::cleanupClass(); +#endif + llinfos << "Cleaning up Media and Textures" << llendflush; //Note: diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 5a42f10c8f..249799bf55 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -350,8 +350,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, LLDataPacker *cached_dpp = NULL; #if LL_RECORD_VIEWER_STATS - static LLViewerStatsRecorder stats_recorder; - stats_recorder.initObjectUpdateEvents(regionp); + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp); #endif for (i = 0; i < num_objects; i++) @@ -368,7 +367,8 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); // Lookup data packer and add this id to cache miss lists if necessary. - cached_dpp = regionp->getDP(id, crc); + U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; + cached_dpp = regionp->getDP(id, crc, cache_miss_type); if (cached_dpp) { // Cache Hit. @@ -381,8 +381,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { // Cache Miss. #if LL_RECORD_VIEWER_STATS - const BOOL success = TRUE; - stats_recorder.recordObjectUpdateEvent(regionp, id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type); #endif continue; // no data packer, skip this object @@ -503,8 +502,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { // llinfos << "terse update for an unknown object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -518,8 +516,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { // llinfos << "terse update for an unknown object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -532,8 +529,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mNumDeadObjectUpdates++; // llinfos << "update for a dead object:" << fullid << llendl; #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -543,8 +539,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (!objectp) { #if LL_RECORD_VIEWER_STATS - const BOOL success = FALSE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL); + LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type); #endif continue; } @@ -584,13 +579,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); } #if LL_RECORD_VIEWER_STATS - const BOOL success = TRUE; - stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, objectp); + LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp); #endif } #if LL_RECORD_VIEWER_STATS - stats_recorder.closeObjectUpdateEvents(regionp); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); #endif LLVOAvatar::cullAvatarsByPixelArea(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ca07e7c4cf..da2373c39d 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -59,6 +59,7 @@ #include "llurldispatcher.h" #include "llviewerobjectlist.h" #include "llviewerparceloverlay.h" +#include "llviewerstatsrecorder.h" #include "llvlmanager.h" #include "llvlcomposition.h" #include "llvocache.h" @@ -1074,7 +1075,7 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary // Get data packer for this object, if we have cached data // AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) +LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) { llassert(mCacheLoaded); @@ -1087,17 +1088,20 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) { // Record a hit entry->recordHit(); + cache_miss_type = CACHE_MISS_TYPE_NONE; return entry->getDP(crc); } else { // llinfos << "CRC miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_CRC; mCacheMissCRC.put(local_id); } } else { // llinfos << "Cache miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_FULL; mCacheMissFull.put(local_id); } return NULL; @@ -1119,9 +1123,6 @@ void LLViewerRegion::requestCacheMisses() S32 blocks = 0; S32 i; - const U8 CACHE_MISS_TYPE_FULL = 0; - const U8 CACHE_MISS_TYPE_CRC = 1; - // Send full cache miss updates. For these, we KNOW we don't // have a viewer object. for (i = 0; i < full_count; i++) @@ -1184,6 +1185,11 @@ void LLViewerRegion::requestCacheMisses() mCacheDirty = TRUE ; // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); + LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); + #endif } void LLViewerRegion::dumpCache() diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 8b71998f60..7fac2020ee 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -274,9 +274,16 @@ public: void getInfo(LLSD& info); + typedef enum + { + CACHE_MISS_TYPE_FULL = 0, + CACHE_MISS_TYPE_CRC, + CACHE_MISS_TYPE_NONE + } eCacheMissType; + // handle a full update message void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); - LLDataPacker *getDP(U32 local_id, U32 crc); + LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type); void requestCacheMisses(); void addCacheMissFull(const U32 local_id); diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 1b80a2bc1c..27bbc17b36 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -30,43 +30,73 @@ #include "llviewerregion.h" #include "llviewerobject.h" + +// To do - something using region name or global position +#if LL_WINDOWS + static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv"); +#else + static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv"); +#endif + + +LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL; LLViewerStatsRecorder::LLViewerStatsRecorder() : mObjectCacheFile(NULL), - mTimer() + mTimer(), + mRegionp(NULL), + mStartTime(0.f), + mProcessingTime(0.f) { - mStartTime = LLTimer::getTotalTime(); + if (NULL != sInstance) + { + llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl; + } + sInstance = this; + clearStats(); } LLViewerStatsRecorder::~LLViewerStatsRecorder() { - LLFile::close(mObjectCacheFile); - mObjectCacheFile = NULL; + if (mObjectCacheFile != NULL) + { + LLFile::close(mObjectCacheFile); + mObjectCacheFile = NULL; + } } +// static +void LLViewerStatsRecorder::initClass() +{ + sInstance = new LLViewerStatsRecorder(); +} -void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) +// static +void LLViewerStatsRecorder::cleanupClass() { - // To do - something using region name or global position -#if LL_WINDOWS - std::string stats_file_name("C:\\ViewerObjectCacheStats.csv"); -#else - std::string stats_file_name("/tmp/viewerstats.csv"); -#endif + delete sInstance; + sInstance = NULL; +} + +void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) +{ if (mObjectCacheFile == NULL) { - mObjectCacheFile = LLFile::fopen(stats_file_name, "wb"); + mStartTime = LLTimer::getTotalTime(); + mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb"); if (mObjectCacheFile) { // Write column headers std::ostringstream data_msg; data_msg << "EventTime, " << "ProcessingTime, " << "CacheHits, " - << "CacheMisses, " + << "CacheFullMisses, " + << "CacheCrcMisses, " << "FullUpdates, " << "TerseUpdates, " + << "CacheMissRequests, " << "CacheMissResponses, " - << "TotalUpdates " + << "UpdateFailures" << "\n"; fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); @@ -74,58 +104,83 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) } } - -void LLViewerStatsRecorder::initObjectUpdateEvents(LLViewerRegion *regionp) +void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp) { initStatsRecorder(regionp); + mRegionp = regionp; + mProcessingTime = LLTimer::getTotalTime(); + clearStats(); +} + +void LLViewerStatsRecorder::clearStats() +{ mObjectCacheHitCount = 0; - mObjectCacheMissCount = 0; + mObjectCacheMissFullCount = 0; + mObjectCacheMissCrcCount = 0; mObjectFullUpdates = 0; mObjectTerseUpdates = 0; + mObjectCacheMissRequests = 0; mObjectCacheMissResponses = 0; - mProcessingTime = LLTimer::getTotalTime(); + mObjectUpdateFailures = 0; } -void LLViewerStatsRecorder::recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp) +void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type) +{ + mObjectUpdateFailures++; +} + +void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type) { - if (!objectp) + if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type) { - // no object, must be a miss - mObjectCacheMissCount++; + mObjectCacheMissFullCount++; } else - { - switch (update_type) - { - case OUT_FULL: - mObjectFullUpdates++; - break; - case OUT_TERSE_IMPROVED: - mObjectTerseUpdates++; - break; - case OUT_FULL_COMPRESSED: - mObjectCacheMissResponses++; - break; - case OUT_FULL_CACHED: - default: - mObjectCacheHitCount++; - break; - }; + { + mObjectCacheMissCrcCount++; } } -void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp) +void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp) +{ + switch (update_type) + { + case OUT_FULL: + mObjectFullUpdates++; + break; + case OUT_TERSE_IMPROVED: + mObjectTerseUpdates++; + break; + case OUT_FULL_COMPRESSED: + mObjectCacheMissResponses++; + break; + case OUT_FULL_CACHED: + default: + mObjectCacheHitCount++; + break; + }; +} + +void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count) +{ + mObjectCacheMissRequests += count; +} + +void LLViewerStatsRecorder::endObjectUpdateEvents() { llinfos << "ILX: " << mObjectCacheHitCount << " hits, " - << mObjectCacheMissCount << " misses, " + << mObjectCacheMissFullCount << " full misses, " + << mObjectCacheMissCrcCount << " crc misses, " << mObjectFullUpdates << " full updates, " << mObjectTerseUpdates << " terse updates, " - << mObjectCacheMissResponses << " cache miss responses" + << mObjectCacheMissRequests << " cache miss requests, " + << mObjectCacheMissResponses << " cache miss responses, " + << mObjectUpdateFailures << " update failures" << llendl; - S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissResponses;; + S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectUpdateFailures; if (mObjectCacheFile != NULL && total_objects > 0) { @@ -136,18 +191,19 @@ void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp) data_msg << now32 << ", " << processing32 << ", " << mObjectCacheHitCount - << ", " << mObjectCacheMissCount + << ", " << mObjectCacheMissFullCount + << ", " << mObjectCacheMissCrcCount << ", " << mObjectFullUpdates << ", " << mObjectTerseUpdates + << ", " << mObjectCacheMissRequests << ", " << mObjectCacheMissResponses - << ", " << total_objects + << ", " << mObjectUpdateFailures << "\n"; fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); } - mObjectCacheHitCount = 0; - mObjectCacheMissCount = 0; + clearStats(); } diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index 213d15f963..001b8d9bd6 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -39,6 +39,7 @@ #include "llframetimer.h" #include "llviewerobject.h" +class LLMutex; class LLViewerRegion; class LLViewerObject; @@ -48,24 +49,41 @@ class LLViewerStatsRecorder LLViewerStatsRecorder(); ~LLViewerStatsRecorder(); + static void initClass(); + static void cleanupClass(); + static LLViewerStatsRecorder* instance() {return sInstance; } + void initStatsRecorder(LLViewerRegion *regionp); - void initObjectUpdateEvents(LLViewerRegion *regionp); - void recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp); - void closeObjectUpdateEvents(LLViewerRegion *regionp); + void beginObjectUpdateEvents(LLViewerRegion *regionp); + void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type); + void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type); + void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp); + void recordRequestCacheMissesEvent(S32 count); + void endObjectUpdateEvents(); private: - LLFrameTimer mTimer; - F64 mStartTime; - F64 mProcessingTime; - - LLFILE * mObjectCacheFile; // File to write data into - S32 mObjectCacheHitCount; - S32 mObjectCacheMissCount; - S32 mObjectFullUpdates; - S32 mObjectTerseUpdates; - S32 mObjectCacheMissResponses; + static LLViewerStatsRecorder* sInstance; + + LLFILE * mObjectCacheFile; // File to write data into + LLFrameTimer mTimer; + LLViewerRegion* mRegionp; + F64 mStartTime; + F64 mProcessingTime; + + S32 mObjectCacheHitCount; + S32 mObjectCacheMissFullCount; + S32 mObjectCacheMissCrcCount; + S32 mObjectFullUpdates; + S32 mObjectTerseUpdates; + S32 mObjectCacheMissRequests; + S32 mObjectCacheMissResponses; + S32 mObjectUpdateFailures; + + + void clearStats(); }; #endif // LL_RECORD_VIEWER_STATS #endif // LLVIEWERSTATSRECORDER_H + -- cgit v1.3 From e04f9ef1093287155f1d0820bd63c4b3c6c5d3d2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 14 Dec 2010 19:27:43 -0500 Subject: SWAT-352: when loading lleventhost, call apr_dso_error() function. In addition to its usual apr_sterror() function, APR defines a special function specifically for errors relating to the apr_dso_*() functions. Introduce ll_apr_warn_status() and ll_apr_assert_status() overloads accepting apr_dso_handle_t* to call apr_dso_error() as well as apr_strerror() and log its output. Use new ll_apr_warn_status() in LLAppViewer::loadEventHostModule() for apr_dso_load() and apr_dso_sym() calls. Instead of shorthand ll_apr_assert_status(), use with llassert_always() so check is still performed even in Release build. Add more lleventhost-related debugging output, e.g. full pathname of the DLL. On Mac and Linux, call 'file' command to report nature of the DLL too. --- indra/llcommon/llapr.cpp | 22 ++++++++++++++++++++-- indra/llcommon/llapr.h | 5 +++++ indra/newview/llappviewer.cpp | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 66ec5bad2c..d1c44c9403 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "llapr.h" +#include "apr_dso.h" apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. @@ -279,14 +280,31 @@ bool ll_apr_warn_status(apr_status_t status) { if(APR_SUCCESS == status) return false; char buf[MAX_STRING]; /* Flawfinder: ignore */ - apr_strerror(status, buf, MAX_STRING); + apr_strerror(status, buf, sizeof(buf)); LL_WARNS("APR") << "APR: " << buf << LL_ENDL; return true; } +bool ll_apr_warn_status(apr_status_t status, apr_dso_handle_t *handle) +{ + bool result = ll_apr_warn_status(status); + // Despite observed truncation of actual Mac dylib load errors, increasing + // this buffer to more than MAX_STRING doesn't help: it appears that APR + // stores the output in a fixed 255-character internal buffer. (*sigh*) + char buf[MAX_STRING]; /* Flawfinder: ignore */ + apr_dso_error(handle, buf, sizeof(buf)); + LL_WARNS("APR") << "APR: " << buf << LL_ENDL; + return result; +} + void ll_apr_assert_status(apr_status_t status) { - llassert(ll_apr_warn_status(status) == false); + llassert(! ll_apr_warn_status(status)); +} + +void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle) +{ + llassert(! ll_apr_warn_status(status, handle)); } //--------------------------------------------------------------------- diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 4930270af8..af33ce666f 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -53,6 +53,8 @@ extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; extern apr_thread_mutex_t* gCallStacksLogMutexp; +struct apr_dso_handle_t; + /** * @brief initialize the common apr constructs -- apr itself, the * global pool, and a mutex. @@ -259,8 +261,11 @@ public: * @return Returns true if status is an error condition. */ bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); +/// There's a whole other APR error-message function if you pass a DSO handle. +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle); void LL_COMMON_API ll_apr_assert_status(apr_status_t status); +void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle); extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index eb8d87e184..a6953a47f0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4622,6 +4622,35 @@ void LLAppViewer::loadEventHostModule(S32 listen_port) return; } + LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL; +#if ! defined(LL_WINDOWS) + { + std::string outfile("/tmp/lleventhost.file.out"); + std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1"); + int rc = system(command.c_str()); + if (rc != 0) + { + LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL; + } + else + { + LL_INFOS("eventhost") << command << ':' << LL_ENDL; + } + { + std::ifstream reader(outfile.c_str()); + std::string line; + while (std::getline(reader, line)) + { + size_t len = line.length(); + if (len && line[len-1] == '\n') + line.erase(len-1); + LL_INFOS("eventhost") << line << LL_ENDL; + } + } + remove(outfile.c_str()); + } +#endif // LL_WINDOWS + apr_dso_handle_t * eventhost_dso_handle = NULL; apr_pool_t * eventhost_dso_memory_pool = NULL; @@ -4630,13 +4659,13 @@ void LLAppViewer::loadEventHostModule(S32 listen_port) apr_status_t rv = apr_dso_load(&eventhost_dso_handle, dso_path.c_str(), eventhost_dso_memory_pool); - ll_apr_assert_status(rv); + llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle)); llassert_always(eventhost_dso_handle != NULL); int (*ll_plugin_start_func)(LLSD const &) = NULL; rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start"); - ll_apr_assert_status(rv); + llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle)); llassert_always(ll_plugin_start_func != NULL); LLSD args; -- cgit v1.3 From 6f996302ef5f8277dbfab9a75a536b554d7fa4e9 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Wed, 15 Dec 2010 13:24:47 -0800 Subject: don't ask before quitting when login or download progress is being shown. --- indra/newview/llappviewer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a6953a47f0..5cf7087c71 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -81,6 +81,7 @@ #include "llurlmatch.h" #include "lltextutil.h" #include "lllogininstance.h" +#include "llprogressview.h" #include "llweb.h" #include "llsecondlifeurls.h" @@ -3138,7 +3139,7 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q void LLAppViewer::userQuit() { - if (gDisconnected) + if (gDisconnected || gViewerWindow->getProgressView()->getVisible()) { requestQuit(); } -- cgit v1.3 From 1774489ef8c224359e39d6281497e5128b043d24 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Thu, 16 Dec 2010 09:34:19 -0800 Subject: Vary install failed message depending on whether it was required or not. --- indra/newview/llappviewer.cpp | 11 ++++++++++- indra/newview/skins/default/xui/en/notifications.xml | 13 +++++++++++++ indra/viewer_components/updater/llupdateinstaller.cpp | 7 ++++++- indra/viewer_components/updater/llupdateinstaller.h | 7 ++++--- indra/viewer_components/updater/llupdaterservice.cpp | 8 ++++++++ .../viewer_components/updater/scripts/darwin/update_install | 2 +- .../viewer_components/updater/scripts/linux/update_install | 2 +- .../updater/scripts/windows/update_install.bat | 2 +- .../updater/tests/llupdaterservice_test.cpp | 2 +- 9 files changed, 45 insertions(+), 9 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5cf7087c71..c9800c9830 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2475,6 +2475,11 @@ namespace { LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback); } + + void install_error_callback(LLSD const & notification, LLSD const & response) + { + LLAppViewer::instance()->forceQuit(); + } bool notify_update(LLSD const & evt) { @@ -2485,7 +2490,11 @@ namespace { on_update_downloaded(evt); break; case LLUpdaterService::INSTALL_ERROR: - LLNotificationsUtil::add("FailedUpdateInstall"); + if(evt["required"].asBoolean()) { + LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback); + } else { + LLNotificationsUtil::add("FailedUpdateInstall"); + } break; default: break; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b0bb93c13a..fc5479a6f7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2888,6 +2888,19 @@ http://secondlife.com/download. yestext="OK"/> + +We were unable to install a required update. +You will be unable to log in until [APP_NAME] has been updated. +Please download and install the latest viewer from +http://secondlife.com/download. + + + +#include #include "llapr.h" #include "llprocesslauncher.h" #include "llupdateinstaller.h" @@ -47,7 +48,10 @@ namespace { } -int ll_install_update(std::string const & script, std::string const & updatePath, LLInstallScriptMode mode) +int ll_install_update(std::string const & script, + std::string const & updatePath, + bool required, + LLInstallScriptMode mode) { std::string actualScriptPath; switch(mode) { @@ -73,6 +77,7 @@ int ll_install_update(std::string const & script, std::string const & updatePath launcher.setExecutable(actualScriptPath); launcher.addArgument(updatePath); launcher.addArgument(ll_install_failed_marker_path().c_str()); + launcher.addArgument(boost::lexical_cast(required)); int result = launcher.launch(); launcher.orphan(); diff --git a/indra/viewer_components/updater/llupdateinstaller.h b/indra/viewer_components/updater/llupdateinstaller.h index 6ce08ce6fa..fe5b1d19b5 100644 --- a/indra/viewer_components/updater/llupdateinstaller.h +++ b/indra/viewer_components/updater/llupdateinstaller.h @@ -42,9 +42,10 @@ enum LLInstallScriptMode { // that the current application terminate once this function is called. // int ll_install_update( - std::string const & script, // Script to execute. - std::string const & updatePath, // Path to update file. - LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp? + std::string const & script, // Script to execute. + std::string const & updatePath, // Path to update file. + bool required, // Is the update required. + LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp? // diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index df1a963f81..08f76c26e9 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -305,6 +305,7 @@ bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller) int result = ll_install_update(install_script_path(), update_info["path"].asString(), + update_info["required"].asBoolean(), install_script_mode()); if((result == 0) && mAppExitCallback) @@ -489,6 +490,12 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event) // Check for failed install. if(LLFile::isfile(ll_install_failed_marker_path())) { + int requiredValue = 0; + { + llifstream stream(ll_install_failed_marker_path()); + stream >> requiredValue; + if(!stream) requiredValue = 0; + } // TODO: notify the user. llinfos << "found marker " << ll_install_failed_marker_path() << llendl; llinfos << "last install attempt failed" << llendl; @@ -496,6 +503,7 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event) LLSD event; event["type"] = LLSD(LLUpdaterService::INSTALL_ERROR); + event["required"] = LLSD(requiredValue); LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).post(event); setState(LLUpdaterService::TERMINAL); diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install index 9df382f119..6a95f96d86 100644 --- a/indra/viewer_components/updater/scripts/darwin/update_install +++ b/indra/viewer_components/updater/scripts/darwin/update_install @@ -6,5 +6,5 @@ # cd "$(dirname "$0")" -../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2" -marker "$2" & +(../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2"; if [ $? -ne 0 ]; then echo $3 >> "$2"; fi;) & exit 0 diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install index a271926e25..88451340ec 100644 --- a/indra/viewer_components/updater/scripts/linux/update_install +++ b/indra/viewer_components/updater/scripts/linux/update_install @@ -4,7 +4,7 @@ export LD_LIBRARY_PATH="$INSTALL_DIR/lib" bin/linux-updater.bin --file "$1" --dest "$INSTALL_DIR" --name "Second Life Viewer 2" --stringsdir "$INSTALL_DIR/skins/default/xui/en" --stringsfile "strings.xml" if [ $? -ne 0 ] - then touch "$2" + then echo $3 >> "$2" fi rm -f "$1" diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat index 42e148a707..96687226a8 100644 --- a/indra/viewer_components/updater/scripts/windows/update_install.bat +++ b/indra/viewer_components/updater/scripts/windows/update_install.bat @@ -1,3 +1,3 @@ start /WAIT %1 /SKIP_DIALOGS -IF ERRORLEVEL 1 ECHO %ERRORLEVEL% > %2 +IF ERRORLEVEL 1 ECHO %3 > %2 DEL %1 diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index be5a5da50d..5f8cd28f29 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -103,7 +103,7 @@ void LLUpdateDownloader::resume(void) {} void LLUpdateDownloader::cancel(void) {} void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {} -int ll_install_update(std::string const &, std::string const &, LLInstallScriptMode) +int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode) { return 0; } -- cgit v1.3 From 376ee7a3f9a07f584386e45516645ce3acbe3cb6 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Thu, 30 Dec 2010 18:18:33 +0200 Subject: STORM-797 FIXED Added parcel SLURL rendering with human readable parcel names. - Added parcel info observer to LLUrlEntryParcel. - Added notifying LLUrlEntryParcel by LLRemoteParcelInfoProcessor when parcel data arrives. - Added notifying LLUrlEntryParcel about user login, changing host and viewer connection state to use this data in remote parcel requests. --- indra/llui/llurlentry.cpp | 83 ++++++++++++++++++++++ indra/llui/llurlentry.h | 39 ++++++++++ indra/llui/tests/llurlentry_stub.cpp | 18 +++++ indra/newview/llagent.cpp | 5 ++ indra/newview/llappviewer.cpp | 5 ++ indra/newview/llremoteparcelrequest.cpp | 13 ++++ indra/newview/llstartup.cpp | 9 +++ indra/newview/tests/llremoteparcelrequest_test.cpp | 2 + 8 files changed, 174 insertions(+) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 4f7b4be526..06b3c17967 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -36,6 +36,7 @@ #include "llcachename.h" #include "lltrans.h" #include "lluicolortable.h" +#include "message.h" #define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" @@ -740,6 +741,13 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const return LLUrlEntryBase::getLocation(url); } +// LLUrlEntryParcel statics. +LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null); +LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); +LLHost LLUrlEntryParcel::sRegionHost(LLHost::invalid); +bool LLUrlEntryParcel::sDisconnected(false); +std::set LLUrlEntryParcel::sParcelInfoObservers; + /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about @@ -751,13 +759,88 @@ LLUrlEntryParcel::LLUrlEntryParcel() boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_parcel.xml"; mTooltip = LLTrans::getString("TooltipParcelUrl"); + + sParcelInfoObservers.insert(this); +} + +LLUrlEntryParcel::~LLUrlEntryParcel() +{ + sParcelInfoObservers.erase(this); } std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { + LLSD path_array = LLURI(url).pathArray(); + S32 path_parts = path_array.size(); + + if (path_parts < 3) // no parcel id + { + llwarns << "Failed to parse url [" << url << "]" << llendl; + return url; + } + + std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id + + // Add an observer to call LLUrlLabelCallback when we have parcel name. + addObserver(parcel_id_string, url, cb); + + LLUUID parcel_id(parcel_id_string); + + sendParcelInfoRequest(parcel_id); + return unescapeUrl(url); } +void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id) +{ + if (sRegionHost == LLHost::invalid || sDisconnected) return; + + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("ParcelInfoRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, sAgentID ); + msg->addUUID("SessionID", sSessionID); + msg->nextBlock("Data"); + msg->addUUID("ParcelID", parcel_id); + msg->sendReliable(sRegionHost); +} + +void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label) +{ + callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon); +} + +// static +void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) +{ + std::string label(LLStringUtil::null); + if (!parcel_data.name.empty()) + { + label = parcel_data.name; + } + // If parcel name is empty use Sim_name (x, y, z) for parcel label. + else if (!parcel_data.sim_name.empty()) + { + S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS; + S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS; + S32 region_z = llround(parcel_data.global_z); + + label = llformat("%s (%d, %d, %d)", + parcel_data.sim_name.c_str(), region_x, region_y, region_z); + } + + for (std::set::iterator iter = sParcelInfoObservers.begin(); + iter != sParcelInfoObservers.end(); + ++iter) + { + LLUrlEntryParcel* url_entry = *iter; + if (url_entry) + { + url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); + } + } +} + // // LLUrlEntryPlace Describes secondlife:// URLs // diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 1791739061..5f82721c0f 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -31,6 +31,9 @@ #include "lluuid.h" #include "lluicolor.h" #include "llstyle.h" + +#include "llhost.h" // for resolving parcel name by parcel id + #include #include #include @@ -285,8 +288,44 @@ private: class LLUrlEntryParcel : public LLUrlEntryBase { public: + struct LLParcelData + { + LLUUID parcel_id; + std::string name; + std::string sim_name; + F32 global_x; + F32 global_y; + F32 global_z; + }; + LLUrlEntryParcel(); + ~LLUrlEntryParcel(); /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + + // Sends a parcel info request to sim. + void sendParcelInfoRequest(const LLUUID& parcel_id); + + // Calls observers of certain parcel id providing them with parcel label. + void onParcelInfoReceived(const std::string &id, const std::string &label); + + // Processes parcel label and triggers notifying observers. + static void processParcelInfo(const LLParcelData& parcel_data); + + // Next 4 setters are used to update agent and viewer connection information + // upon events like user login, viewer disconnect and user changing region host. + // These setters are made public to be accessible from newview and should not be + // used in other cases. + static void setAgentID(const LLUUID& id) { sAgentID = id; } + static void setSessionID(const LLUUID& id) { sSessionID = id; } + static void setRegionHost(const LLHost& host) { sRegionHost = host; } + static void setDisconnected(bool disconnected) { sDisconnected = disconnected; } + +private: + static LLUUID sAgentID; + static LLUUID sSessionID; + static LLHost sRegionHost; + static bool sDisconnected; + static std::set sParcelInfoObservers; }; /// diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index f30704cb22..96ebe83826 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -30,6 +30,7 @@ #include "llavatarnamecache.h" #include "llcachename.h" #include "lluuid.h" +#include "message.h" #include @@ -191,3 +192,20 @@ LLFontGL* LLFontGL::getFontDefault() { return NULL; } + +char* _PREHASH_AgentData = "AgentData"; +char* _PREHASH_AgentID = "AgentID"; + +LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS); + +LLMessageSystem* gMessageSystem = NULL; + +// +// Stub implementation for LLMessageSystem +// +void LLMessageSystem::newMessage(const char *name) { } +void LLMessageSystem::nextBlockFast(const char *blockname) { } +void LLMessageSystem::nextBlock(const char *blockname) { } +void LLMessageSystem::addUUIDFast( const char *varname, const LLUUID& uuid) { } +void LLMessageSystem::addUUID( const char *varname, const LLUUID& uuid) { } +S32 LLMessageSystem::sendReliable(const LLHost &host) { return 0; } diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 77552663ab..7d908df5ce 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -64,6 +64,7 @@ #include "lltool.h" #include "lltoolmgr.h" #include "lltrans.h" +#include "llurlentry.h" #include "llviewercontrol.h" #include "llviewerdisplay.h" #include "llviewerjoystick.h" @@ -649,6 +650,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp) } mRegionp = regionp; + // Pass the region host to LLUrlEntryParcel to resolve parcel name + // with a server request. + LLUrlEntryParcel::setRegionHost(getRegionHost()); + // Must shift hole-covering water object locations because local // coordinate frame changed. LLWorld::getInstance()->updateWaterObjects(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a98c23e05..729f83a2b1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -93,6 +93,7 @@ #include "llmemory.h" #include "llprimitive.h" #include "llurlaction.h" +#include "llurlentry.h" #include "llvfile.h" #include "llvfsthread.h" #include "llvolumemgr.h" @@ -4567,6 +4568,10 @@ void LLAppViewer::disconnectViewer() cleanup_xfer_manager(); gDisconnected = TRUE; + + // Pass the connection state to LLUrlEntryParcel not to attempt + // parcel info requests while disconnected. + LLUrlEntryParcel::setDisconnected(gDisconnected); } void LLAppViewer::forceErrorLLError() diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index e5ef51bdd1..3862dac340 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -33,6 +33,7 @@ #include "llpanel.h" #include "llhttpclient.h" #include "llsdserialize.h" +#include "llurlentry.h" #include "llviewerregion.h" #include "llview.h" @@ -168,6 +169,18 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v { observers.erase(*i); } + + LLUrlEntryParcel::LLParcelData url_data; + url_data.parcel_id = parcel_data.parcel_id; + url_data.name = parcel_data.name; + url_data.sim_name = parcel_data.sim_name; + url_data.global_x = parcel_data.global_x; + url_data.global_y = parcel_data.global_y; + url_data.global_z = parcel_data.global_z; + + // Pass the parcel data to LLUrlEntryParcel to render + // human readable parcel name. + LLUrlEntryParcel::processParcelInfo(url_data); } void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 611f9de2e6..5617eea4c3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -139,6 +139,7 @@ #include "lltrans.h" #include "llui.h" #include "llurldispatcher.h" +#include "llurlentry.h" #include "llslurl.h" #include "llurlhistory.h" #include "llurlwhitelist.h" @@ -2882,9 +2883,17 @@ bool process_login_success_response() if(!text.empty()) gAgentID.set(text); gDebugInfo["AgentID"] = text; + // Agent id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setAgentID(gAgentID); + text = response["session_id"].asString(); if(!text.empty()) gAgentSessionID.set(text); gDebugInfo["SessionID"] = text; + + // Session id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setSessionID(gAgentSessionID); text = response["secure_session_id"].asString(); if(!text.empty()) gAgent.mSecureSessionID.set(text); diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index dae22521bb..7862cce3a1 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -32,6 +32,7 @@ #include "../llagent.h" #include "message.h" +#include "llurlentry.h" namespace { LLControlGroup s_saved_settings("dummy_settings"); @@ -72,6 +73,7 @@ LLUIColor::LLUIColor(void) { } LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { } LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker(name) { } LLControlGroup::~LLControlGroup(void) { } +void LLUrlEntryParcel::processParcelInfo(const LLUrlEntryParcel::LLParcelData& parcel_data) { } namespace tut { -- cgit v1.3 From 4af9db7b79f5721d1be6b8b94dd1e0ce97782d79 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Tue, 11 Jan 2011 19:50:58 +0200 Subject: STORM-477 FIXED Re-implemented LLDir::getNextFileInDir() as an iterator object. - Replaced all existing usages of LLDir::getNextFileInDir() with the new directory iterator object. - Removed platform specific LLDir::getNextFileInDir() implementation. --- .../llui_libtest/llui_libtest.cpp | 5 +- indra/linux_updater/linux_updater.cpp | 15 ++++-- indra/llvfs/lldir.cpp | 6 ++- indra/llvfs/lldir.h | 25 --------- indra/llvfs/lldir_linux.cpp | 62 ---------------------- indra/llvfs/lldir_linux.h | 1 - indra/llvfs/lldir_mac.cpp | 61 --------------------- indra/llvfs/lldir_mac.h | 1 - indra/llvfs/lldir_solaris.cpp | 62 ---------------------- indra/llvfs/lldir_solaris.h | 1 - indra/llvfs/lldir_win32.cpp | 61 --------------------- indra/llvfs/lldir_win32.h | 3 -- indra/newview/llappviewer.cpp | 8 ++- indra/newview/llappviewerlinux.cpp | 5 +- indra/newview/llfloateruipreview.cpp | 26 ++++++--- indra/newview/lllogchat.cpp | 4 +- indra/newview/llviewermedia.cpp | 4 +- indra/newview/llwaterparammanager.cpp | 11 ++-- indra/newview/llwlparammanager.cpp | 11 ++-- .../updater/tests/llupdaterservice_test.cpp | 6 --- 20 files changed, 68 insertions(+), 310 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index c34115ee80..217e26c3ca 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -33,6 +33,7 @@ // linden library includes #include "llcontrol.h" // LLControlGroup #include "lldir.h" +#include "lldiriterator.h" #include "llerrorcontrol.h" #include "llfloater.h" #include "llfontfreetype.h" @@ -174,7 +175,9 @@ void export_test_floaters() std::string delim = gDirUtilp->getDirDelimiter(); std::string xui_dir = get_xui_dir() + "en" + delim; std::string filename; - while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename)) + + LLDirIterator iter(xui_dir, "floater_test_*.xml"); + while (iter.next(filename)) { if (filename.find("_new.xml") != std::string::npos) { diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index d909516bf8..808ab3f64f 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -33,6 +33,7 @@ #include "llerrorcontrol.h" #include "llfile.h" #include "lldir.h" +#include "lldiriterator.h" #include "llxmlnode.h" #include "lltrans.h" @@ -55,6 +56,8 @@ typedef struct _updater_app_state { std::string strings_dirs; std::string strings_file; + LLDirIterator *image_dir_iter; + GtkWidget *window; GtkWidget *progress_bar; GtkWidget *image; @@ -108,7 +111,7 @@ bool translate_init(std::string comma_delim_path_list, void updater_app_ui_init(void); void updater_app_quit(UpdaterAppState *app_state); void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); -std::string next_image_filename(std::string& image_path); +std::string next_image_filename(std::string& image_path, LLDirIterator& iter); void display_error(GtkWidget *parent, std::string title, std::string message); BOOL install_package(std::string package_file, std::string destination); BOOL spawn_viewer(UpdaterAppState *app_state); @@ -174,7 +177,7 @@ void updater_app_ui_init(UpdaterAppState *app_state) // load the first image app_state->image = gtk_image_new_from_file - (next_image_filename(app_state->image_dir).c_str()); + (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str()); gtk_widget_set_size_request(app_state->image, 340, 310); gtk_container_add(GTK_CONTAINER(frame), app_state->image); @@ -205,7 +208,7 @@ gboolean rotate_image_cb(gpointer data) llassert(data != NULL); app_state = (UpdaterAppState *) data; - filename = next_image_filename(app_state->image_dir); + filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter); gdk_threads_enter(); gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); @@ -214,10 +217,10 @@ gboolean rotate_image_cb(gpointer data) return TRUE; } -std::string next_image_filename(std::string& image_path) +std::string next_image_filename(std::string& image_path, LLDirIterator& iter) { std::string image_filename; - gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename); + iter.next(image_filename); return image_path + "/" + image_filename; } @@ -741,6 +744,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc)) { app_state->image_dir = argv[i]; + app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg"); } else if ((!strcmp(argv[i], "--dest")) && (++i < argc)) { @@ -825,6 +829,7 @@ int main(int argc, char **argv) } bool success = !app_state->failure; + delete app_state->image_dir_iter; delete app_state; return success ? 0 : 1; } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 64556bcb4c..ab7d15dfef 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -40,6 +40,8 @@ #include "lltimer.h" // ms_sleep() #include "lluuid.h" +#include "lldiriterator.h" + #if LL_WINDOWS #include "lldir_win32.h" LLDir_Win32 gDirUtil; @@ -83,7 +85,9 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) std::string filename; std::string fullpath; S32 result; - while (getNextFileInDir(dirname, mask, filename)) + + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) { fullpath = dirname; fullpath += getDirDelimiter(); diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 42996fd051..5ee8bdb542 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -75,31 +75,6 @@ class LLDir // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; - /// Walk the files in a directory, with file pattern matching - virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash! - const std::string& mask, ///< file pattern string (use "*" for all) - std::string& fname ///< output: found file name - ) = 0; - /**< - * @returns true if a file was found, false if the entire directory has been scanned. - * - * @note that this function is NOT thread safe - * - * This function may not be used to scan part of a directory, then start a new search of a different - * directory, and then restart the first search where it left off; the entire search must run to - * completion or be abandoned - there is no restart. - * - * @bug: See http://jira.secondlife.com/browse/VWR-23697 - * and/or the tests in test/lldir_test.cpp - * This is known to fail with patterns that have both: - * a wildcard left of a . and more than one sequential ? right of a . - * the pattern foo.??x appears to work - * but *.??x or foo?.??x do not - * - * @todo this really should be rewritten as an iterator object, and the - * filtering should be done in a platform-independent way. - */ - virtual std::string getCurPath() = 0; virtual BOOL fileExists(const std::string &filename) const = 0; diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 73f2336f94..4ba2f519b0 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -242,68 +242,6 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } -// get the next file in the directory -BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if((int)g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < (int)g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - - std::string LLDir_Linux::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index 451e81ae93..ff4c48759a 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -43,7 +43,6 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 445285aa43..2d039527c0 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -258,67 +258,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma return (file_count); } -// get the next file in the directory -BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if(g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask) { glob_t g; diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index 4eac3c3ae6..e60d5e41c2 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -43,7 +43,6 @@ public: virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 515fd66b6e..21f8c3acdb 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -260,68 +260,6 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string return (file_count); } -// get the next file in the directory -BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if((int)g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < (int)g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - - std::string LLDir_Solaris::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index 4a1794f539..f7e1a6301d 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -43,7 +43,6 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; private: diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 33718e520d..2f96fbbbc1 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -236,67 +236,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } - -// get the next file in the directory -BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - BOOL fileFound = FALSE; - fname = ""; - - WIN32_FIND_DATAW FileData; - llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask); - - if (pathname != mCurrentDir) - { - // different dir specified, close old search - if (mCurrentDir[0]) - { - FindClose(mDirSearch_h); - } - mCurrentDir = pathname; - - // and open new one - // Check error opening Directory structure - if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE) - { - fileFound = TRUE; - } - } - - // Loop to skip over the current (.) and parent (..) directory entries - // (apparently returned in Win7 but not XP) - do - { - if ( fileFound - && ( (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0) - ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0) - ) - ) - { - fileFound = FALSE; - } - } while ( mDirSearch_h != INVALID_HANDLE_VALUE - && !fileFound - && (fileFound = FindNextFile(mDirSearch_h, &FileData) - ) - ); - - if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES) - { - // No more files, so reset to beginning of directory - FindClose(mDirSearch_h); - mCurrentDir[0] = '\000'; - } - - if (fileFound) - { - // convert from TCHAR to char - fname = utf16str_to_utf8str(FileData.cFileName); - } - - return fileFound; -} - std::string LLDir_Win32::getCurPath() { WCHAR w_str[MAX_PATH]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 4c932c932c..19c610eb8b 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -40,15 +40,12 @@ public: /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: - BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); - void* mDirSearch_h; llutf16string mCurrentDir; }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a98c23e05..b5248316a1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -89,6 +89,7 @@ // Linden library includes #include "llavatarnamecache.h" +#include "lldiriterator.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" @@ -3290,7 +3291,9 @@ void LLAppViewer::migrateCacheDirectory() S32 file_count = 0; std::string file_name; std::string mask = delimiter + "*.*"; - while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name)) + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -3509,7 +3512,8 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string found_file; - if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) + LLDirIterator iter(dir, mask); + if (iter.next(found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 898cc1c0ba..fc7a27e5e0 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -30,6 +30,7 @@ #include "llcommandlineparser.h" +#include "lldiriterator.h" #include "llmemtype.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" @@ -504,7 +505,9 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; - while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name)) + + LLDirIterator iter(uuiddir, "*"); + while (iter.next(this_name)) { if (this_name.length() > best.length() || (this_name.length() == best.length() && diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 11b3379814..182d3d23f1 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -35,6 +35,7 @@ #include "llfloateruipreview.h" // Own header // Internal utility +#include "lldiriterator.h" #include "lleventtimer.h" #include "llexternaleditor.h" #include "llrender.h" @@ -481,9 +482,11 @@ BOOL LLFloaterUIPreview::postBuild() std::string language_directory; std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + + LLDirIterator iter(xui_dir, "*"); while(found) // for every directory { - if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory))) // get next directory + if((found = iter.next(language_directory))) // get next directory { std::string full_path = xui_dir + language_directory; if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it @@ -635,42 +638,51 @@ void LLFloaterUIPreview::refreshList() mFileList->clearRows(); // empty list std::string name; BOOL found = TRUE; + + LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); while(found) // for every floater file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name))) // get next file matching pattern + if((found = floater_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); while(found) // for every inspector file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name))) // get next file matching pattern + if((found = inspect_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); while(found) // for every menu file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name))) // get next file matching pattern + if((found = menu_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); while(found) // for every panel file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name))) // get next file matching pattern + if((found = panel_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } - found = TRUE; + + LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); while(found) // for every sidepanel file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name))) // get next file matching pattern + if((found = sidepanel_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 9adf374c71..b09cfbe907 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,6 +32,7 @@ #include "lltrans.h" #include "llviewercontrol.h" +#include "lldiriterator.h" #include "llinstantmessage.h" #include "llsingleton.h" // for LLSingleton @@ -601,7 +602,8 @@ std::string LLLogChat::oldLogFileName(std::string filename) //LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */ std::vector allfiles; - while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult)) + LLDirIterator iter(directory, pattern); + while (iter.next(scanResult)) { //LL_INFOS("") << "Found :" << scanResult << LL_ENDL; allfiles.push_back(scanResult); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d3b6dcd86f..8a0d0a6623 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -54,6 +54,7 @@ #include "llfilepicker.h" #include "llnotifications.h" +#include "lldiriterator.h" #include "llevent.h" // LLSimpleListener #include "llnotificationsutil.h" #include "lluuid.h" @@ -1115,7 +1116,8 @@ void LLViewerMedia::clearAllCookies() } // the hard part: iterate over all user directories and delete the cookie file from each one - while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) + LLDirIterator dir_iter(base_dir, "*_*"); + while (dir_iter.next(filename)) { target = base_dir; target += filename; diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index d239347810..4f6ec4ca61 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -33,6 +33,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -85,11 +86,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; - bool found = true; + bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); + found = app_settings_iter.next(name); if(found) { @@ -111,11 +113,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; - found = true; + found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index e5f52dfc97..848efcbb49 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -31,6 +31,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -100,11 +101,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; - bool found = true; + bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); + found = app_settings_iter.next(name); if(found) { @@ -126,11 +128,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; - found = true; + found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 88ab5a2284..e19d5724f1 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -59,12 +59,6 @@ class LLDir_Mock : public LLDir return 0; } - BOOL getNextFileInDir(const std::string &dirname, - const std::string &mask, - std::string &fname) - { - return false; - } void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) {} -- cgit v1.3 From 804495ad41cbd0eb511c02d5306fc3b8f9be0b89 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 13 Jan 2011 11:15:47 -0800 Subject: STORM-477 : backout changeset 6f5cb303d3e2 --- .../llui_libtest/llui_libtest.cpp | 5 +- indra/linux_updater/linux_updater.cpp | 15 ++---- indra/llvfs/lldir.cpp | 6 +-- indra/llvfs/lldir.h | 25 +++++++++ indra/llvfs/lldir_linux.cpp | 62 ++++++++++++++++++++++ indra/llvfs/lldir_linux.h | 1 + indra/llvfs/lldir_mac.cpp | 61 +++++++++++++++++++++ indra/llvfs/lldir_mac.h | 1 + indra/llvfs/lldir_solaris.cpp | 62 ++++++++++++++++++++++ indra/llvfs/lldir_solaris.h | 1 + indra/llvfs/lldir_win32.cpp | 61 +++++++++++++++++++++ indra/llvfs/lldir_win32.h | 3 ++ indra/newview/llappviewer.cpp | 8 +-- indra/newview/llappviewerlinux.cpp | 5 +- indra/newview/llfloateruipreview.cpp | 26 +++------ indra/newview/lllogchat.cpp | 4 +- indra/newview/llviewermedia.cpp | 4 +- indra/newview/llwaterparammanager.cpp | 11 ++-- indra/newview/llwlparammanager.cpp | 11 ++-- .../updater/tests/llupdaterservice_test.cpp | 6 +++ 20 files changed, 310 insertions(+), 68 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index 217e26c3ca..c34115ee80 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -33,7 +33,6 @@ // linden library includes #include "llcontrol.h" // LLControlGroup #include "lldir.h" -#include "lldiriterator.h" #include "llerrorcontrol.h" #include "llfloater.h" #include "llfontfreetype.h" @@ -175,9 +174,7 @@ void export_test_floaters() std::string delim = gDirUtilp->getDirDelimiter(); std::string xui_dir = get_xui_dir() + "en" + delim; std::string filename; - - LLDirIterator iter(xui_dir, "floater_test_*.xml"); - while (iter.next(filename)) + while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename)) { if (filename.find("_new.xml") != std::string::npos) { diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index 808ab3f64f..d909516bf8 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -33,7 +33,6 @@ #include "llerrorcontrol.h" #include "llfile.h" #include "lldir.h" -#include "lldiriterator.h" #include "llxmlnode.h" #include "lltrans.h" @@ -56,8 +55,6 @@ typedef struct _updater_app_state { std::string strings_dirs; std::string strings_file; - LLDirIterator *image_dir_iter; - GtkWidget *window; GtkWidget *progress_bar; GtkWidget *image; @@ -111,7 +108,7 @@ bool translate_init(std::string comma_delim_path_list, void updater_app_ui_init(void); void updater_app_quit(UpdaterAppState *app_state); void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); -std::string next_image_filename(std::string& image_path, LLDirIterator& iter); +std::string next_image_filename(std::string& image_path); void display_error(GtkWidget *parent, std::string title, std::string message); BOOL install_package(std::string package_file, std::string destination); BOOL spawn_viewer(UpdaterAppState *app_state); @@ -177,7 +174,7 @@ void updater_app_ui_init(UpdaterAppState *app_state) // load the first image app_state->image = gtk_image_new_from_file - (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str()); + (next_image_filename(app_state->image_dir).c_str()); gtk_widget_set_size_request(app_state->image, 340, 310); gtk_container_add(GTK_CONTAINER(frame), app_state->image); @@ -208,7 +205,7 @@ gboolean rotate_image_cb(gpointer data) llassert(data != NULL); app_state = (UpdaterAppState *) data; - filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter); + filename = next_image_filename(app_state->image_dir); gdk_threads_enter(); gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); @@ -217,10 +214,10 @@ gboolean rotate_image_cb(gpointer data) return TRUE; } -std::string next_image_filename(std::string& image_path, LLDirIterator& iter) +std::string next_image_filename(std::string& image_path) { std::string image_filename; - iter.next(image_filename); + gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename); return image_path + "/" + image_filename; } @@ -744,7 +741,6 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc)) { app_state->image_dir = argv[i]; - app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg"); } else if ((!strcmp(argv[i], "--dest")) && (++i < argc)) { @@ -829,7 +825,6 @@ int main(int argc, char **argv) } bool success = !app_state->failure; - delete app_state->image_dir_iter; delete app_state; return success ? 0 : 1; } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index ab7d15dfef..64556bcb4c 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -40,8 +40,6 @@ #include "lltimer.h" // ms_sleep() #include "lluuid.h" -#include "lldiriterator.h" - #if LL_WINDOWS #include "lldir_win32.h" LLDir_Win32 gDirUtil; @@ -85,9 +83,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) std::string filename; std::string fullpath; S32 result; - - LLDirIterator iter(dirname, mask); - while (iter.next(filename)) + while (getNextFileInDir(dirname, mask, filename)) { fullpath = dirname; fullpath += getDirDelimiter(); diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 5ee8bdb542..42996fd051 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -75,6 +75,31 @@ class LLDir // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; + /// Walk the files in a directory, with file pattern matching + virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash! + const std::string& mask, ///< file pattern string (use "*" for all) + std::string& fname ///< output: found file name + ) = 0; + /**< + * @returns true if a file was found, false if the entire directory has been scanned. + * + * @note that this function is NOT thread safe + * + * This function may not be used to scan part of a directory, then start a new search of a different + * directory, and then restart the first search where it left off; the entire search must run to + * completion or be abandoned - there is no restart. + * + * @bug: See http://jira.secondlife.com/browse/VWR-23697 + * and/or the tests in test/lldir_test.cpp + * This is known to fail with patterns that have both: + * a wildcard left of a . and more than one sequential ? right of a . + * the pattern foo.??x appears to work + * but *.??x or foo?.??x do not + * + * @todo this really should be rewritten as an iterator object, and the + * filtering should be done in a platform-independent way. + */ + virtual std::string getCurPath() = 0; virtual BOOL fileExists(const std::string &filename) const = 0; diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 4ba2f519b0..73f2336f94 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -242,6 +242,68 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } +// get the next file in the directory +BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + glob_t g; + BOOL result = FALSE; + fname = ""; + + if(!(dirname == mCurrentDir)) + { + // different dir specified, close old search + mCurrentDirIndex = -1; + mCurrentDirCount = -1; + mCurrentDir = dirname; + } + + std::string tmp_str; + tmp_str = dirname; + tmp_str += mask; + + if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) + { + if(g.gl_pathc > 0) + { + if((int)g.gl_pathc != mCurrentDirCount) + { + // Number of matches has changed since the last search, meaning a file has been added or deleted. + // Reset the index. + mCurrentDirIndex = -1; + mCurrentDirCount = g.gl_pathc; + } + + mCurrentDirIndex++; + + if(mCurrentDirIndex < (int)g.gl_pathc) + { +// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + + // The API wants just the filename, not the full path. + //fname = g.gl_pathv[mCurrentDirIndex]; + + char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); + + if(s == NULL) + s = g.gl_pathv[mCurrentDirIndex]; + else if(s[0] == '/') + s++; + + fname = s; + + result = TRUE; + } + } + + globfree(&g); + } + + return(result); +} + + + + std::string LLDir_Linux::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index ff4c48759a..451e81ae93 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -43,6 +43,7 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 2d039527c0..445285aa43 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -258,6 +258,67 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma return (file_count); } +// get the next file in the directory +BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + glob_t g; + BOOL result = FALSE; + fname = ""; + + if(!(dirname == mCurrentDir)) + { + // different dir specified, close old search + mCurrentDirIndex = -1; + mCurrentDirCount = -1; + mCurrentDir = dirname; + } + + std::string tmp_str; + tmp_str = dirname; + tmp_str += mask; + + if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) + { + if(g.gl_pathc > 0) + { + if(g.gl_pathc != mCurrentDirCount) + { + // Number of matches has changed since the last search, meaning a file has been added or deleted. + // Reset the index. + mCurrentDirIndex = -1; + mCurrentDirCount = g.gl_pathc; + } + + mCurrentDirIndex++; + + if(mCurrentDirIndex < g.gl_pathc) + { +// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + + // The API wants just the filename, not the full path. + //fname = g.gl_pathv[mCurrentDirIndex]; + + char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); + + if(s == NULL) + s = g.gl_pathv[mCurrentDirIndex]; + else if(s[0] == '/') + s++; + + fname = s; + + result = TRUE; + } + } + + globfree(&g); + } + + return(result); +} + + + S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask) { glob_t g; diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index e60d5e41c2..4eac3c3ae6 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -43,6 +43,7 @@ public: virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 21f8c3acdb..515fd66b6e 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -260,6 +260,68 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string return (file_count); } +// get the next file in the directory +BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + glob_t g; + BOOL result = FALSE; + fname = ""; + + if(!(dirname == mCurrentDir)) + { + // different dir specified, close old search + mCurrentDirIndex = -1; + mCurrentDirCount = -1; + mCurrentDir = dirname; + } + + std::string tmp_str; + tmp_str = dirname; + tmp_str += mask; + + if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) + { + if(g.gl_pathc > 0) + { + if((int)g.gl_pathc != mCurrentDirCount) + { + // Number of matches has changed since the last search, meaning a file has been added or deleted. + // Reset the index. + mCurrentDirIndex = -1; + mCurrentDirCount = g.gl_pathc; + } + + mCurrentDirIndex++; + + if(mCurrentDirIndex < (int)g.gl_pathc) + { +// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; + + // The API wants just the filename, not the full path. + //fname = g.gl_pathv[mCurrentDirIndex]; + + char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); + + if(s == NULL) + s = g.gl_pathv[mCurrentDirIndex]; + else if(s[0] == '/') + s++; + + fname = s; + + result = TRUE; + } + } + + globfree(&g); + } + + return(result); +} + + + + std::string LLDir_Solaris::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index f7e1a6301d..4a1794f539 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -43,6 +43,7 @@ public: public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; private: diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 2f96fbbbc1..33718e520d 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -236,6 +236,67 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } + +// get the next file in the directory +BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) +{ + BOOL fileFound = FALSE; + fname = ""; + + WIN32_FIND_DATAW FileData; + llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask); + + if (pathname != mCurrentDir) + { + // different dir specified, close old search + if (mCurrentDir[0]) + { + FindClose(mDirSearch_h); + } + mCurrentDir = pathname; + + // and open new one + // Check error opening Directory structure + if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE) + { + fileFound = TRUE; + } + } + + // Loop to skip over the current (.) and parent (..) directory entries + // (apparently returned in Win7 but not XP) + do + { + if ( fileFound + && ( (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0) + ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0) + ) + ) + { + fileFound = FALSE; + } + } while ( mDirSearch_h != INVALID_HANDLE_VALUE + && !fileFound + && (fileFound = FindNextFile(mDirSearch_h, &FileData) + ) + ); + + if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES) + { + // No more files, so reset to beginning of directory + FindClose(mDirSearch_h); + mCurrentDir[0] = '\000'; + } + + if (fileFound) + { + // convert from TCHAR to char + fname = utf16str_to_utf8str(FileData.cFileName); + } + + return fileFound; +} + std::string LLDir_Win32::getCurPath() { WCHAR w_str[MAX_PATH]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 19c610eb8b..4c932c932c 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -40,12 +40,15 @@ public: /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); + /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: + BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); + void* mDirSearch_h; llutf16string mCurrentDir; }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f0711db3bd..729f83a2b1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -89,7 +89,6 @@ // Linden library includes #include "llavatarnamecache.h" -#include "lldiriterator.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" @@ -3292,9 +3291,7 @@ void LLAppViewer::migrateCacheDirectory() S32 file_count = 0; std::string file_name; std::string mask = delimiter + "*.*"; - - LLDirIterator iter(old_cache_dir, mask); - while (iter.next(file_name)) + while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -3513,8 +3510,7 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string found_file; - LLDirIterator iter(dir, mask); - if (iter.next(found_file)) + if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index fc7a27e5e0..898cc1c0ba 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -30,7 +30,6 @@ #include "llcommandlineparser.h" -#include "lldiriterator.h" #include "llmemtype.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" @@ -505,9 +504,7 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; - - LLDirIterator iter(uuiddir, "*"); - while (iter.next(this_name)) + while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name)) { if (this_name.length() > best.length() || (this_name.length() == best.length() && diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 182d3d23f1..11b3379814 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -35,7 +35,6 @@ #include "llfloateruipreview.h" // Own header // Internal utility -#include "lldiriterator.h" #include "lleventtimer.h" #include "llexternaleditor.h" #include "llrender.h" @@ -482,11 +481,9 @@ BOOL LLFloaterUIPreview::postBuild() std::string language_directory; std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim mLanguageSelection->removeall(); // clear out anything temporarily in list from XML - - LLDirIterator iter(xui_dir, "*"); while(found) // for every directory { - if((found = iter.next(language_directory))) // get next directory + if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory))) // get next directory { std::string full_path = xui_dir + language_directory; if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it @@ -638,51 +635,42 @@ void LLFloaterUIPreview::refreshList() mFileList->clearRows(); // empty list std::string name; BOOL found = TRUE; - - LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); while(found) // for every floater file that matches the pattern { - if((found = floater_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; - - LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); while(found) // for every inspector file that matches the pattern { - if((found = inspect_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; - - LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); while(found) // for every menu file that matches the pattern { - if((found = menu_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; - - LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); while(found) // for every panel file that matches the pattern { - if((found = panel_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } - found = TRUE; - LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); + found = TRUE; while(found) // for every sidepanel file that matches the pattern { - if((found = sidepanel_iter.next(name))) // get next file matching pattern + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index b09cfbe907..9adf374c71 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,7 +32,6 @@ #include "lltrans.h" #include "llviewercontrol.h" -#include "lldiriterator.h" #include "llinstantmessage.h" #include "llsingleton.h" // for LLSingleton @@ -602,8 +601,7 @@ std::string LLLogChat::oldLogFileName(std::string filename) //LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */ std::vector allfiles; - LLDirIterator iter(directory, pattern); - while (iter.next(scanResult)) + while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult)) { //LL_INFOS("") << "Found :" << scanResult << LL_ENDL; allfiles.push_back(scanResult); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 8a0d0a6623..d3b6dcd86f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -54,7 +54,6 @@ #include "llfilepicker.h" #include "llnotifications.h" -#include "lldiriterator.h" #include "llevent.h" // LLSimpleListener #include "llnotificationsutil.h" #include "lluuid.h" @@ -1116,8 +1115,7 @@ void LLViewerMedia::clearAllCookies() } // the hard part: iterate over all user directories and delete the cookie file from each one - LLDirIterator dir_iter(base_dir, "*_*"); - while (dir_iter.next(filename)) + while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) { target = base_dir; target += filename; diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 4f6ec4ca61..d239347810 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -33,7 +33,6 @@ #include "pipeline.h" #include "llsky.h" -#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -86,12 +85,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; - bool found = true; - LLDirIterator app_settings_iter(path_name, "*.xml"); + bool found = true; while(found) { std::string name; - found = app_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); if(found) { @@ -113,12 +111,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; - found = true; - LLDirIterator user_settings_iter(path_name2, "*.xml"); + found = true; while(found) { std::string name; - found = user_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 848efcbb49..e5f52dfc97 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -31,7 +31,6 @@ #include "pipeline.h" #include "llsky.h" -#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -101,12 +100,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; - bool found = true; - LLDirIterator app_settings_iter(path_name, "*.xml"); + bool found = true; while(found) { std::string name; - found = app_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); if(found) { @@ -128,12 +126,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; - found = true; - LLDirIterator user_settings_iter(path_name2, "*.xml"); + found = true; while(found) { std::string name; - found = user_settings_iter.next(name); + found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index e19d5724f1..88ab5a2284 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -59,6 +59,12 @@ class LLDir_Mock : public LLDir return 0; } + BOOL getNextFileInDir(const std::string &dirname, + const std::string &mask, + std::string &fname) + { + return false; + } void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) {} -- cgit v1.3 From e1066784220adb9a2e731001e72c444582fc997f Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Sun, 16 Jan 2011 21:41:08 -0500 Subject: DN-202: Make avatar name caching more aggressive and error handling more uniform Add logging (mostly at DEBUG level) --- indra/llmessage/llavatarnamecache.cpp | 258 ++++++++++++++++++++-------------- indra/llmessage/llavatarnamecache.h | 3 + indra/newview/llappviewer.cpp | 1 + 3 files changed, 159 insertions(+), 103 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index d9cb83c089..ab4785569d 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -38,6 +38,7 @@ #include #include +#include namespace LLAvatarNameCache { @@ -81,8 +82,11 @@ namespace LLAvatarNameCache // only need per-frame timing resolution LLFrameTimer sRequestTimer; - // Periodically clean out expired entries from the cache - //LLFrameTimer sEraseExpiredTimer; + /// Maximum time an unrefreshed cache entry is allowed + const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0; + + /// Time when unrefreshed cached names were checked last + static F64 sLastExpireCheck; //----------------------------------------------------------------------- // Internal methods @@ -99,8 +103,9 @@ namespace LLAvatarNameCache // Legacy name system callback void legacyNameCallback(const LLUUID& agent_id, - const std::string& full_name, - bool is_group); + const std::string& full_name, + bool is_group + ); void requestNamesViaLegacy(); @@ -117,7 +122,7 @@ namespace LLAvatarNameCache bool isRequestPending(const LLUUID& agent_id); // Erase expired names from cache - void eraseExpired(); + void eraseUnrefreshed(); bool expirationFromCacheControl(LLSD headers, F64 *expires); } @@ -187,6 +192,7 @@ public: { // Pull expiration out of headers if available F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders); + F64 now = LLFrameTimer::getTotalSeconds(); LLSD agents = content["agents"]; LLSD::array_const_iterator it = agents.beginArray(); @@ -207,84 +213,91 @@ public: av_name.mDisplayName = av_name.mUsername; } + LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " " + << "user '" << av_name.mUsername << "' " + << "display '" << av_name.mDisplayName << "' " + << "expires in " << expires - now << " seconds" + << LL_ENDL; + // cache it and fire signals LLAvatarNameCache::processName(agent_id, av_name, true); } // Same logic as error response case LLSD unresolved_agents = content["bad_ids"]; - if (unresolved_agents.size() > 0) + S32 num_unresolved = unresolved_agents.size(); + if (num_unresolved > 0) { - const std::string DUMMY_NAME("\?\?\?"); - LLAvatarName av_name; - av_name.mUsername = DUMMY_NAME; - av_name.mDisplayName = DUMMY_NAME; - av_name.mIsDisplayNameDefault = false; - av_name.mIsTemporaryName = true; - av_name.mExpires = expires; - + LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " + << "expires in " << expires - now << " seconds" + << LL_ENDL; it = unresolved_agents.beginArray(); for ( ; it != unresolved_agents.endArray(); ++it) { const LLUUID& agent_id = *it; - // cache it and fire signals - LLAvatarNameCache::processName(agent_id, av_name, true); + + LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " + << "failed id " << agent_id + << LL_ENDL; + + LLAvatarNameCache::handleAgentError(agent_id); } } - } + LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result " + << LLAvatarNameCache::sCache.size() << " cached names" + << LL_ENDL; + } /*virtual*/ void error(U32 status, const std::string& reason) { // If there's an error, it might be caused by PeopleApi, // or when loading textures on startup and using a very slow - // network, this query may time out. Fallback to the legacy - // cache. - - llwarns << "LLAvatarNameResponder error " << status << " " << reason << llendl; + // network, this query may time out. + // What we should do depends on whether or not we have a cached name + LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason + << LL_ENDL; - // Add dummy records for all agent IDs in this request + // Add dummy records for any agent IDs in this request that we do not have cached already std::vector::const_iterator it = mAgentIDs.begin(); for ( ; it != mAgentIDs.end(); ++it) { const LLUUID& agent_id = *it; - gCacheName->get(agent_id, false, // legacy compatibility - boost::bind(&LLAvatarNameCache::legacyNameCallback, - _1, _2, _3)); + LLAvatarNameCache::handleAgentError(agent_id); } } - - // Return time to retry a request that generated an error, based on - // error type and headers. Return value is seconds-since-epoch. - F64 errorRetryTimestamp(S32 status) - { - F64 now = LLFrameTimer::getTotalSeconds(); - - // Retry-After takes priority - LLSD retry_after = mHeaders["retry-after"]; - if (retry_after.isDefined()) - { - // We only support the delta-seconds type - S32 delta_seconds = retry_after.asInteger(); - if (delta_seconds > 0) - { - // ...valid delta-seconds - return now + F64(delta_seconds); - } - } - - // If no Retry-After, look for Cache-Control max-age - F64 expires = 0.0; - if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires)) - { - return expires; - } - - // No information in header, make a guess - const F64 DEFAULT_DELAY = 120.0; // 2 mintues - return now + DEFAULT_DELAY; - } }; +// Provide some fallback for agents that return errors +void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) +{ + std::map::iterator existing = sCache.find(agent_id); + if (existing == sCache.end()) + { + // there is no existing cache entry, so make a temporary name from legacy + LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent " + << agent_id << LL_ENDL; + gCacheName->get(agent_id, false, // legacy compatibility + boost::bind(&LLAvatarNameCache::legacyNameCallback, + _1, _2, _3)); + } + else + { + // we have a chached (but probably expired) entry - since that would have + // been returned by the get method, there is no need to signal anyone + + // Clear this agent from the pending list + LLAvatarNameCache::sPendingQueue.erase(agent_id); + + const LLAvatarName& av_name = existing->second; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " + << agent_id + << "user '" << av_name.mUsername << "' " + << "display '" << av_name.mDisplayName << "' " + << "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds" + << LL_ENDL; + } +} + void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& av_name, bool add_to_cache) @@ -326,6 +339,7 @@ void LLAvatarNameCache::requestNamesViaCapability() std::vector agent_ids; agent_ids.reserve(128); + U32 ids = 0; ask_queue_t::const_iterator it = sAskQueue.begin(); for ( ; it != sAskQueue.end(); ++it) { @@ -336,11 +350,13 @@ void LLAvatarNameCache::requestNamesViaCapability() // ...starting new request url += sNameLookupURL; url += "?ids="; + ids = 1; } else { // ...continuing existing request url += "&ids="; + ids++; } url += agent_id.asString(); agent_ids.push_back(agent_id); @@ -350,8 +366,10 @@ void LLAvatarNameCache::requestNamesViaCapability() if (url.size() > NAME_URL_SEND_THRESHOLD) { - //llinfos << "requestNames " << url << llendl; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));//, LLSD(), 10.0f); + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first " + << ids << " ids" + << LL_ENDL; + LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } @@ -359,8 +377,10 @@ void LLAvatarNameCache::requestNamesViaCapability() if (!url.empty()) { - //llinfos << "requestNames " << url << llendl; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));//, LLSD(), 10.0f); + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all " + << ids << " ids" + << LL_ENDL; + LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } @@ -376,6 +396,11 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, // Construct a dummy record for this name. By convention, SLID is blank // Never expires, but not written to disk, so lasts until end of session. LLAvatarName av_name; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback " + << "agent " << agent_id << " " + << "full name '" << full_name << "'" + << ( is_group ? " [group]" : "" ) + << LL_ENDL; buildLegacyName(full_name, &av_name); // Don't add to cache, the data already exists in the legacy name system @@ -397,6 +422,8 @@ void LLAvatarNameCache::requestNamesViaLegacy() // invoked below. This should never happen in practice. sPendingQueue[agent_id] = now; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL; + gCacheName->get(agent_id, false, // legacy compatibility boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3)); @@ -435,21 +462,24 @@ void LLAvatarNameCache::importFile(std::istream& istr) av_name.fromLLSD( it->second ); sCache[agent_id] = av_name; } - // entries may have expired since we last ran the viewer, just - // clean them out now - eraseExpired(); - llinfos << "loaded " << sCache.size() << llendl; + // Some entries may have expired since the cache was stored, + // but next time they are read that will be checked. + // Expired entries are filtered out when the cache is stored, + // or in eraseUnrefreshed + LL_INFOS("AvNameCache") << "loaded " << sCache.size() << LL_ENDL; } void LLAvatarNameCache::exportFile(std::ostream& ostr) { LLSD agents; + F64 now = LLFrameTimer::getTotalSeconds(); cache_t::const_iterator it = sCache.begin(); for ( ; it != sCache.end(); ++it) { const LLUUID& agent_id = it->first; const LLAvatarName& av_name = it->second; - if (!av_name.mIsTemporaryName) + // Do not write temporary or expired entries to the stored cache + if (!av_name.mIsTemporaryName && av_name.mExpires >= now) { // key must be a string agents[agent_id.asString()] = av_name.asLLSD(); @@ -484,56 +514,63 @@ void LLAvatarNameCache::idle() // return; //} - // Must be large relative to above - - // No longer deleting expired entries, just re-requesting in the get - // this way first synchronous get call on an expired entry won't return - // legacy name. LF - - if (sAskQueue.empty()) + if (!sAskQueue.empty()) { - return; + if (useDisplayNames()) + { + requestNamesViaCapability(); + } + else + { + // ...fall back to legacy name cache system + requestNamesViaLegacy(); + } } - if (useDisplayNames()) - { - requestNamesViaCapability(); - } - else - { - // ...fall back to legacy name cache system - requestNamesViaLegacy(); - } + // erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME + eraseUnrefreshed(); } bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id) { + bool isPending = false; const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; - F64 now = LLFrameTimer::getTotalSeconds(); - F64 expire_time = now - PENDING_TIMEOUT_SECS; pending_queue_t::const_iterator it = sPendingQueue.find(agent_id); if (it != sPendingQueue.end()) { - bool request_expired = (it->second < expire_time); - return !request_expired; + // in the list of requests in flight, retry if too old + F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; + isPending = (it->second > expire_time); } - return false; + return isPending; } -void LLAvatarNameCache::eraseExpired() +void LLAvatarNameCache::eraseUnrefreshed() { F64 now = LLFrameTimer::getTotalSeconds(); - cache_t::iterator it = sCache.begin(); - while (it != sCache.end()) - { - cache_t::iterator cur = it; - ++it; - const LLAvatarName& av_name = cur->second; - if (av_name.mExpires < now) - { - sCache.erase(cur); - } + F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME; + + if (!sLastExpireCheck || sLastExpireCheck < max_unrefreshed) + { + sLastExpireCheck = now; + cache_t::iterator it = sCache.begin(); + while (it != sCache.end()) + { + cache_t::iterator cur = it; + ++it; + const LLAvatarName& av_name = cur->second; + if (av_name.mExpires < max_unrefreshed) + { + const LLUUID& agent_id = it->first; + LL_DEBUGS("AvNameCache") << agent_id + << " user '" << av_name.mUsername << "' " + << "expired " << now - av_name.mExpires << " secs ago" + << LL_ENDL; + sCache.erase(cur); + } + } + LL_INFOS("AvNameCache") << sCache.size() << " cached avatar names" << LL_ENDL; } } @@ -545,7 +582,10 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name, av_name->mDisplayName = full_name; av_name->mIsDisplayNameDefault = true; av_name->mIsTemporaryName = true; - av_name->mExpires = F64_MAX; + av_name->mExpires = F64_MAX; // not used because these are not cached + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName " + << full_name + << LL_ENDL; } // fills in av_name if it has it in the cache, even if expired (can check expiry time) @@ -568,6 +608,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) { if (!isRequestPending(agent_id)) { + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get " + << "refresh agent " << agent_id + << LL_ENDL; sAskQueue.insert(agent_id); } } @@ -589,6 +632,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) if (!isRequestPending(agent_id)) { + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get " + << "queue request for agent " << agent_id + << LL_ENDL; sAskQueue.insert(agent_id); } @@ -621,7 +667,6 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { // ...name already exists in cache, fire callback now fireSignal(agent_id, slot, av_name); - return; } } @@ -717,6 +762,9 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) { + bool fromCacheControl = false; + F64 now = LLFrameTimer::getTotalSeconds(); + // Allow the header to override the default LLSD cache_control_header = headers["cache-control"]; if (cache_control_header.isDefined()) @@ -725,12 +773,16 @@ bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) std::string cache_control = cache_control_header.asString(); if (max_age_from_cache_control(cache_control, &max_age)) { - F64 now = LLFrameTimer::getTotalSeconds(); *expires = now + (F64)max_age; - return true; + fromCacheControl = true; } } - return false; + LL_DEBUGS("AvNameCache") + << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) + << "in " << *expires - now << " seconds" + << LL_ENDL; + + return fromCacheControl; } diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 8f21ace96a..59c1329ffa 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -82,6 +82,9 @@ namespace LLAvatarNameCache void erase(const LLUUID& agent_id); + /// Provide some fallback for agents that return errors + void handleAgentError(const LLUUID& agent_id); + // Force a re-fetch of the most recent data, but keep the current // data in cache void fetch(const LLUUID& agent_id); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a98c23e05..e92042bcd4 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3734,6 +3734,7 @@ void LLAppViewer::loadNameCache() // display names cache std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + LL_INFOS("AvNameCache") << filename << LL_ENDL; llifstream name_cache_stream(filename); if(name_cache_stream.is_open()) { -- cgit v1.3 From 466413cdf094c78c85a509e70739417d5950210c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 14:44:06 -0500 Subject: VWR-24317: clean up incorrect warnings prior to login in log file --- indra/newview/llappviewer.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d1e9b24ef6..88c57a1433 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3076,35 +3076,32 @@ void LLAppViewer::initMarkerFile() std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning()) { gLastExecEvent = LAST_EXEC_FROZE; LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL; } - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL; gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(logout_marker_file); } if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) { - llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl; if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(llerror_marker_file); } if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL; if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(error_marker_file); } - - LLAPRFile::remove(logout_marker_file); - LLAPRFile::remove(llerror_marker_file); - LLAPRFile::remove(error_marker_file); - + // No new markers if another instance is running. if(anotherInstanceRunning()) { -- cgit v1.3 From ad34f858dc5047a5e4c2fc3dcabbd24f7663e00d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 15:52:37 -0500 Subject: VWR-24317: remove warning re: RenderCubeMap by deferring initialization --- indra/newview/llappviewer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 88c57a1433..e2af22a678 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -473,8 +473,6 @@ static void settings_to_globals() gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale"); - - LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); } static void settings_modify() @@ -854,6 +852,9 @@ bool LLAppViewer::init() gGLActive = TRUE; initWindow(); + // initWindow also initializes the Feature List, so now we can initialize this global. + LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); + // call all self-registered classes LLInitClassList::instance().fireCallbacks(); -- cgit v1.3 From c47ab36b20e102a918257e5fa5452f13bc55a393 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Jan 2011 16:01:27 -0500 Subject: VWR-24320: remove dump of call stack on clean exit --- doc/contributions.txt | 1 + indra/newview/llappviewer.cpp | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'indra/newview/llappviewer.cpp') diff --git a/doc/contributions.txt b/doc/contributions.txt index 3b2e2239d2..1ec878846d 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -82,6 +82,7 @@ Aleric Inglewood VWR-24261 VWR-24315 VWR-24317 + VWR-24320 SNOW-84 SNOW-477 SNOW-744 diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e2af22a678..6a9dfaf21b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1398,16 +1398,6 @@ bool LLAppViewer::cleanup() } mPlugins.clear(); - //---------------------------------------------- - //this test code will be removed after the test - //test manual call stack tracer - if(gSavedSettings.getBOOL("QAMode")) - { - LLError::LLCallStacks::print() ; - } - //end of the test code - //---------------------------------------------- - //flag all elements as needing to be destroyed immediately // to ensure shutdown order LLMortician::setZealous(TRUE); -- cgit v1.3