summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llappviewer.cpp31
-rw-r--r--indra/newview/llsimplestat.h18
-rw-r--r--indra/newview/lltexturefetch.cpp98
-rw-r--r--indra/newview/lltexturefetch.h7
-rw-r--r--indra/newview/llviewerassetstats.cpp286
-rw-r--r--indra/newview/llviewerassetstats.h70
-rw-r--r--indra/newview/tests/llsimplestat_test.cpp158
-rw-r--r--indra/newview/tests/llviewerassetstats_test.cpp595
8 files changed, 740 insertions, 523 deletions
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<VALUE_T> & 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[<region>] without matching dst[<region>]
- 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[<region>] with matching dst[<region>]
- // 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[<region>][<asset>] without matching dst[<region>][<asset>]
- reg_dst[it_sets->first] = it_sets->second;
- }
- else
- {
- // src[<region>][<asset>] with matching dst[<region>][<asset>]
- // 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[<region>][<asset>][<field>]
- continue;
- }
-
- const LLSD & src_value(bin_src[key_name]);
-
- if (! bin_dst.has(key_name))
- {
- // src[<region>][<asset>][<field>] without matching dst[<region>][<asset>][<field>]
- bin_dst[key_name] = src_value;
- }
- else
- {
- // src[<region>][<asset>][<field>] with matching dst[<region>][<asset>][<field>]
- 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<duration_t> 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<region_handle_t, LLPointer<PerRegionStats> > 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<U64> has huge max", (bignum == m1.getMax()));
ensure("Overflowed MMM<U64> 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);
}
}
+
}