diff options
author | Monty Brandenberg <monty@lindenlab.com> | 2010-11-10 08:44:53 -0800 |
---|---|---|
committer | Monty Brandenberg <monty@lindenlab.com> | 2010-11-10 08:44:53 -0800 |
commit | fd2d4dc1b16430edd367a8b0f4162238bbb7e22c (patch) | |
tree | de1c5a1399ee7f1bedade0e2bb437f1816d968da /indra | |
parent | 1ed9d997a6c380f71f2da182c8083321e35b5034 (diff) |
ESC-110 ESC-111
Cleanup passes on the two threaded collectors with better comments
and more complete unit tests.
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/llviewerassetstats.cpp | 172 | ||||
-rw-r--r-- | indra/newview/llviewerassetstats.h | 152 | ||||
-rw-r--r-- | indra/newview/tests/llviewerassetstats_test.cpp | 303 |
3 files changed, 533 insertions, 94 deletions
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index 0852573bbd..a6c4685bf1 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -47,7 +47,7 @@ * <TBD> * * Unit Tests: - * <TBD> + * indra/newview/tests/llviewerassetstats_test.cpp * */ @@ -55,7 +55,8 @@ // ------------------------------------------------------ // Global data definitions // ------------------------------------------------------ -LLViewerAssetStats * gViewerAssetStats = NULL; +LLViewerAssetStats * gViewerAssetStatsMain(0); +LLViewerAssetStats * gViewerAssetStatsThread1(0); // ------------------------------------------------------ @@ -70,6 +71,21 @@ asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool i } // ------------------------------------------------------ +// LLViewerAssetStats::PerRegionStats struct definition +// ------------------------------------------------------ +void +LLViewerAssetStats::PerRegionStats::reset() +{ + for (int i(0); i < LL_ARRAY_SIZE(mRequests); ++i) + { + mRequests[i].mEnqueued.reset(); + mRequests[i].mDequeued.reset(); + mRequests[i].mResponse.reset(); + } +} + + +// ------------------------------------------------------ // LLViewerAssetStats class definition // ------------------------------------------------------ LLViewerAssetStats::LLViewerAssetStats() @@ -81,20 +97,55 @@ LLViewerAssetStats::LLViewerAssetStats() void LLViewerAssetStats::reset() { - for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i) + // Empty the map of all region stats + mRegionStats.clear(); + + // If we have a current stats, reset it, otherwise, as at construction, + // create a new one. + if (mCurRegionStats) { - mRequests[i].mEnqueued.reset(); - mRequests[i].mDequeued.reset(); - mRequests[i].mResponse.reset(); + mCurRegionStats->reset(); } + else + { + mCurRegionStats = new PerRegionStats(mRegionID); + } + + // And add reference to map + mRegionStats[mRegionID] = mCurRegionStats; } + +void +LLViewerAssetStats::setRegionID(const LLUUID & region_id) +{ + if (region_id == mRegionID) + { + // Already active, ignore. + return; + } + + PerRegionContainer::iterator new_stats = mRegionStats.find(region_id); + if (mRegionStats.end() == new_stats) + { + // Haven't seen this region_id before, create a new block make it current. + mCurRegionStats = new PerRegionStats(region_id); + mRegionStats[region_id] = mCurRegionStats; + } + else + { + mCurRegionStats = new_stats->second; + } + mRegionID = region_id; +} + + void LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp) { const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); - ++mRequests[int(eac)].mEnqueued; + ++(mCurRegionStats->mRequests[int(eac)].mEnqueued); } void @@ -102,7 +153,7 @@ LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_htt { const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); - ++mRequests[int(eac)].mDequeued; + ++(mCurRegionStats->mRequests[int(eac)].mDequeued); } void @@ -110,7 +161,7 @@ LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_htt { const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); - mRequests[int(eac)].mResponse.record(duration); + mCurRegionStats->mRequests[int(eac)].mResponse.record(duration); } const LLSD @@ -139,16 +190,33 @@ LLViewerAssetStats::asLLSD() const LLSD ret = LLSD::emptyMap(); - for (int i = 0; i < EVACCount; ++i) + for (PerRegionContainer::const_iterator it = mRegionStats.begin(); + mRegionStats.end() != it; + ++it) { - LLSD & slot = ret[tags[i]]; - slot = LLSD::emptyMap(); - slot[enq_tag] = LLSD(S32(mRequests[i].mEnqueued.getCount())); - slot[deq_tag] = LLSD(S32(mRequests[i].mDequeued.getCount())); - slot[rcnt_tag] = LLSD(S32(mRequests[i].mResponse.getCount())); - slot[rmin_tag] = LLSD(mRequests[i].mResponse.getMin()); - slot[rmax_tag] = LLSD(mRequests[i].mResponse.getMax()); - slot[rmean_tag] = LLSD(mRequests[i].mResponse.getMean()); + if (it->first.isNull()) + { + // Never emit NULL UUID in results. + continue; + } + + const PerRegionStats & stats = *it->second; + + LLSD reg_stat = LLSD::emptyMap(); + + for (int i = 0; i < EVACCount; ++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(stats.mRequests[i].mResponse.getMin()); + slot[rmax_tag] = LLSD(stats.mRequests[i].mResponse.getMax()); + slot[rmean_tag] = LLSD(stats.mRequests[i].mResponse.getMean()); + } + + ret[it->first.asString()] = reg_stat; } return ret; @@ -161,31 +229,81 @@ LLViewerAssetStats::asLLSD() const namespace LLViewerAssetStatsFF { +// Target thread is elaborated in the function name. This could +// have been something 'templatey' like specializations iterated +// over a set of constants but with so few, this is clearer I think. + +void +set_region_main(const LLUUID & region_id) +{ + if (! gViewerAssetStatsMain) + return; + + gViewerAssetStatsMain->setRegionID(region_id); +} + +void +record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ + if (! gViewerAssetStatsMain) + return; + + gViewerAssetStatsMain->recordGetEnqueued(at, with_http, is_temp); +} + +void +record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ + if (! gViewerAssetStatsMain) + return; + + gViewerAssetStatsMain->recordGetDequeued(at, with_http, is_temp); +} + +void +record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration) +{ + if (! gViewerAssetStatsMain) + return; + + gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration); +} + + +void +set_region_thread1(const LLUUID & region_id) +{ + if (! gViewerAssetStatsThread1) + return; + + gViewerAssetStatsThread1->setRegionID(region_id); +} + void -record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp) +record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp) { - if (! gViewerAssetStats) + if (! gViewerAssetStatsThread1) return; - gViewerAssetStats->recordGetEnqueued(at, with_http, is_temp); + gViewerAssetStatsThread1->recordGetEnqueued(at, with_http, is_temp); } void -record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp) +record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp) { - if (! gViewerAssetStats) + if (! gViewerAssetStatsThread1) return; - gViewerAssetStats->recordGetDequeued(at, with_http, is_temp); + gViewerAssetStatsThread1->recordGetDequeued(at, with_http, is_temp); } void -record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration) +record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration) { - if (! gViewerAssetStats) + if (! gViewerAssetStatsThread1) return; - gViewerAssetStats->recordGetServiced(at, with_http, is_temp, duration); + gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration); } } // namespace LLViewerAssetStatsFF diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index 9d66a1e89b..b8356a5ff5 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -36,6 +36,8 @@ #include "linden_common.h" +#include "llpointer.h" +#include "llrefcount.h" #include "llviewerassettype.h" #include "llviewerassetstorage.h" #include "llsimplestat.h" @@ -43,50 +45,42 @@ /** * @class LLViewerAssetStats - * @brief Records events and performance of asset put/get operations. + * @brief Records performance aspects of asset access operations. * - * The asset system is a combination of common code and server- - * and viewer-overridden derivations. The common code is presented - * in here as the 'front-end' and deriviations (really the server) - * are presented as 'back-end'. The distinction isn't perfect as - * there are legacy asset transfer systems which mostly appear - * as front-end stats. + * This facility is derived from a very similar simulator-based + * one, LLSimAssetStats. It's function is to count asset access + * operations and characterize response times. Collected data + * are binned in several dimensions: + * + * - Asset types collapsed into a few aggregated categories + * - By simulator UUID + * - By transport mechanism (HTTP vs MessageSystem) + * - By persistence (temp vs non-temp) + * + * Statistics collected are fairly basic at this point: * - * Statistics collected are fairly basic: * - Counts of enqueue and dequeue operations - * - Counts of duplicated request fetches * - Min/Max/Mean of asset transfer operations * - * While the stats collection interfaces appear to be fairly - * orthogonal across methods (GET, PUT) and asset types (texture, - * bodypart, etc.), the actual internal collection granularity - * varies greatly. GET's operations found in the cache are - * treated as a single group as are duplicate requests. Non- - * cached items are broken down into three groups: textures, - * wearables (bodyparts, clothing) and the rest. PUT operations - * are broken down into two categories: temporary assets and - * non-temp. Back-end operations do not distinguish asset types, - * only GET, PUT (temp) and PUT (non-temp). - * - * No coverage for Estate Assets or Inventory Item Assets which use - * some different interface conventions. It could be expanded to cover - * them. + * This collector differs from the simulator-based on in a + * number of ways: + * + * - The front-end/back-end distinction doesn't exist in viewer + * code + * - Multiple threads must be safely accomodated in the viewer * * Access to results is by conversion to an LLSD with some standardized - * key names. The intent of this structure is to be emitted as + * key names. The intent of this structure is that it be emitted as * standard syslog-based metrics formatting where it can be picked * up by interested parties. * - * For convenience, a set of free functions in namespace LLAssetStatsFF - * are provided which operate on various counters in a way that - * is highly-compatible with the simulator code. + * For convenience, a set of free functions in namespace + * LLViewerAssetStatsFF is provided for conditional test-and-call + * operations. */ class LLViewerAssetStats { public: - LLViewerAssetStats(); - // Default destructor and assignment operator are correct. - enum EViewerAssetCategories { EVACTextureTempHTTPGet, //< Texture GETs @@ -100,45 +94,109 @@ public: EVACCount // Must be last }; - + + /** + * Collected data for a single region visited by the avatar. + */ + class PerRegionStats : public LLRefCount + { + public: + PerRegionStats(const LLUUID & region_id) + : LLRefCount(), + mRegionID(region_id) + { + reset(); + } + + void reset(); + + public: + LLUUID mRegionID; + struct + { + LLSimpleStatCounter mEnqueued; + LLSimpleStatCounter mDequeued; + LLSimpleStatMMM<> mResponse; + } mRequests [EVACCount]; + }; + +public: + LLViewerAssetStats(); + // Default destructor is correct. + LLViewerAssetStats & operator=(const LLViewerAssetStats &); // Not defined + + // Clear all metrics data. This leaves the currently-active region + // in place but with zero'd data for all metrics. All other regions + // are removed from the collection map. void reset(); + // Set hidden region argument and establish context for subsequent + // collection calls. + void setRegionID(const LLUUID & region_id); + // Non-Cached 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, F64 duration); - // Report Generation + // Retrieve current metrics for all visited regions. const LLSD asLLSD() const; protected: + typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer; - struct - { - LLSimpleStatCounter mEnqueued; - LLSimpleStatCounter mDequeued; - LLSimpleStatMMM<> mResponse; - } mRequests [EVACCount]; + // Region of the currently-active region. Always valid but may + // be a NULL UUID after construction or when explicitly set. Unchanged + // by a reset() call. + LLUUID mRegionID; + + // Pointer to metrics collection for currently-active region. Always + // valid and unchanged after reset() though contents will be changed. + // Always points to a collection contained in mRegionStats. + LLPointer<PerRegionStats> mCurRegionStats; + + // Metrics data for all regions during one collection cycle + PerRegionContainer mRegionStats; }; /** - * Expectation is that the simulator and other asset-handling - * code will create a single instance of the stats class and - * make it available here. The free functions examine this - * for non-zero and perform their functions conditionally. The - * instance methods themselves make no assumption about this. + * Global stats collectors one for each independent thread where + * assets and other statistics are gathered. The globals are + * expected to be created at startup time and then picked up by + * their respective threads afterwards. A set of free functions + * are provided to access methods behind the globals while both + * minimally disrupting visual flow and supplying a description + * of intent. + * + * Expected thread assignments: + * + * - Main: main() program execution thread + * - Thread1: TextureFetch worker thread */ -extern LLViewerAssetStats * gViewerAssetStats; +extern LLViewerAssetStats * gViewerAssetStatsMain; + +extern LLViewerAssetStats * gViewerAssetStatsThread1; namespace LLViewerAssetStatsFF { -void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp); +void set_region_main(const LLUUID & region_id); + +void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp); + +void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp); + +void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration); + + +void set_region_thread1(const LLUUID & region_id); + +void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp); -void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp); +void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp); -void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration); +void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration); } // namespace LLViewerAssetStatsFF diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 50d348c7e3..affe16c177 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -38,6 +38,7 @@ #include "lltut.h" #include "../llviewerassetstats.h" +#include "lluuid.h" static const char * all_keys[] = { @@ -73,6 +74,27 @@ static const char * sub_keys[] = "resp_mean" }; +static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8"); +static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a"); + +static bool +is_empty_map(const LLSD & sd) +{ + return sd.isMap() && 0 == sd.size(); +} + +static bool +is_single_key_map(const LLSD & sd, const std::string & key) +{ + return sd.isMap() && 1 == sd.size() && sd.has(key); +} + +static bool +is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & key2) +{ + return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2); +} + namespace tut { struct tst_viewerassetstats_index @@ -86,29 +108,40 @@ namespace tut void tst_viewerassetstats_index_object_t::test<1>() { // Check that helpers aren't bothered by missing global stats - ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats)); + ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); - LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); - LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); - LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_GESTURE, false, false, 12.3); + LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12.3); } // Create a non-global instance and check the structure template<> template<> void tst_viewerassetstats_index_object_t::test<2>() { - ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats)); + ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); LLViewerAssetStats * it = new LLViewerAssetStats(); - ensure("Global gViewerAssetStats should still be NULL", (NULL == gViewerAssetStats)); - - LLSD sd = it->asLLSD(); - - delete it; + ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain)); + LLSD sd_full = it->asLLSD(); + + // 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)); + + // 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()]; + + delete it; + // Check the structure of the LLSD for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i) { @@ -131,8 +164,11 @@ namespace tut void tst_viewerassetstats_index_object_t::test<3>() { LLViewerAssetStats * it = new LLViewerAssetStats(); + it->setRegionID(region1); LLSD sd = it->asLLSD(); + ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); + sd = sd[region1.asString()]; delete it; @@ -145,15 +181,57 @@ namespace tut template<> template<> void tst_viewerassetstats_index_object_t::test<4>() { - gViewerAssetStats = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); + LLViewerAssetStatsFF::set_region_main(region1); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + 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()]; + + // 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())); + ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD()[region1.asString()]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + + ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + } + + // Create two global instances and verify no interactions + template<> template<> + void tst_viewerassetstats_index_object_t::test<5>() + { + gViewerAssetStatsThread1 = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); + LLViewerAssetStatsFF::set_region_main(region1); - LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false); - LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); - LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_BODYPART, false, false); - LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); - LLSD sd = gViewerAssetStats->asLLSD(); + LLSD sd = gViewerAssetStatsThread1->asLLSD(); + ensure("Other collector is empty", is_empty_map(sd)); + sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); + sd = sd[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())); @@ -163,11 +241,196 @@ namespace tut ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); // Reset and check zeros... - gViewerAssetStats->reset(); - sd = gViewerAssetStats->asLLSD(); + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD()[region1.asString()]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + delete gViewerAssetStatsThread1; + gViewerAssetStatsThread1 = NULL; + + ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + } + + // Check multiple region collection + template<> template<> + void tst_viewerassetstats_index_object_t::test<6>() + { + gViewerAssetStatsMain = new LLViewerAssetStats(); + + LLViewerAssetStatsFF::set_region_main(region1); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::set_region_main(region2); + + 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); + + 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()]; + + // 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())); + ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_texture_temp_http][enqueued] is 0", (0 == sd1["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger())); + + // Check a few points on the tree for content + ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); + ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + + // Reset and check zeros... + // 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()]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + + ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + } + + // Check multiple region collection jumping back-and-forth between regions + template<> template<> + void tst_viewerassetstats_index_object_t::test<7>() + { + gViewerAssetStatsMain = new LLViewerAssetStats(); + + LLViewerAssetStatsFF::set_region_main(region1); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::set_region_main(region2); + + 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::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::set_region_main(region2); + + 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); + + 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()]; + + // 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())); + ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_texture_temp_http][enqueued] is 1", (1 == sd1["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger())); + + // Check a few points on the tree for content + ensure("sd2[get_gesture_udp][enqueued] is 8", (8 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); + ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + + // Reset and check zeros... + // 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()]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + + ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + } + + // Non-texture assets ignore transport and persistence flags + template<> template<> + void tst_viewerassetstats_index_object_t::test<8>() + { + gViewerAssetStatsThread1 = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); + LLViewerAssetStatsFF::set_region_main(region1); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, true); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, true); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + LLSD sd = gViewerAssetStatsThread1->asLLSD(); + ensure("Other collector is empty", is_empty_map(sd)); + sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString())); + sd = sd[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())); + ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + + ensure("sd[get_wearable_udp][enqueued] is 4", (4 == sd["get_wearable_udp"]["enqueued"].asInteger())); + ensure("sd[get_wearable_udp][dequeued] is 4", (4 == sd["get_wearable_udp"]["dequeued"].asInteger())); + + ensure("sd[get_other][enqueued] is 4", (4 == sd["get_other"]["enqueued"].asInteger())); + ensure("sd[get_other][dequeued] is 0", (0 == sd["get_other"]["dequeued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD()[region1.asString()]; - delete gViewerAssetStats; - gViewerAssetStats = NULL; + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + delete gViewerAssetStatsThread1; + gViewerAssetStatsThread1 = NULL; ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); |