612 lines
18 KiB
C++
612 lines
18 KiB
C++
/**
|
|
* @file llviewerassetstats.cpp
|
|
* @brief
|
|
*
|
|
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "llviewerassetstats.h"
|
|
#include "llregionhandle.h"
|
|
|
|
#include "stdtypes.h"
|
|
|
|
/*
|
|
* Classes and utility functions for per-thread and per-region
|
|
* asset and experiential metrics to be aggregated grid-wide.
|
|
*
|
|
* The basic metrics grouping is LLViewerAssetStats::PerRegionStats.
|
|
* This provides various counters and simple statistics for asset
|
|
* fetches binned into a few categories. One of these is maintained
|
|
* for each region encountered and the 'current' region is available
|
|
* as a simple reference. Each thread (presently two) interested
|
|
* in participating in these stats gets an instance of the
|
|
* LLViewerAssetStats class so that threads are completely
|
|
* independent.
|
|
*
|
|
* The idea of a current region is used for simplicity and speed
|
|
* of categorization. Each metrics event could have taken a
|
|
* region uuid argument resulting in a suitable lookup. Arguments
|
|
* against this design include:
|
|
*
|
|
* - Region uuid not trivially available to caller.
|
|
* - Cost (cpu, disruption in real work flow) too high.
|
|
* - Additional precision not really meaningful.
|
|
*
|
|
* By itself, the LLViewerAssetStats class is thread- and
|
|
* viewer-agnostic and can be used anywhere without assumptions
|
|
* of global pointers and other context. For the viewer,
|
|
* a set of free functions are provided in the namespace
|
|
* LLViewerAssetStatsFF which *do* implement viewer-native
|
|
* policies about per-thread globals and will do correct
|
|
* defensive tests of same.
|
|
*
|
|
* References
|
|
*
|
|
* Project:
|
|
* <TBD>
|
|
*
|
|
* Test Plan:
|
|
* <TBD>
|
|
*
|
|
* Jiras:
|
|
* <TBD>
|
|
*
|
|
* Unit Tests:
|
|
* indra/newview/tests/llviewerassetstats_test.cpp
|
|
*
|
|
*/
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// Global data definitions
|
|
// ------------------------------------------------------
|
|
LLViewerAssetStats * gViewerAssetStatsMain(0);
|
|
LLViewerAssetStats * gViewerAssetStatsThread1(0);
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// Local declarations
|
|
// ------------------------------------------------------
|
|
namespace
|
|
{
|
|
|
|
static LLViewerAssetStats::EViewerAssetCategories
|
|
asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp);
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// 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();
|
|
}
|
|
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)
|
|
{
|
|
mTotalTime += (now - mStartTimestamp);
|
|
mStartTimestamp = now;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// LLViewerAssetStats class definition
|
|
// ------------------------------------------------------
|
|
LLViewerAssetStats::LLViewerAssetStats()
|
|
: mRegionHandle(U64(0))
|
|
{
|
|
reset();
|
|
}
|
|
|
|
|
|
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()
|
|
{
|
|
// 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 as we must always have a current stats block.
|
|
if (mCurRegionStats)
|
|
{
|
|
mCurRegionStats->reset();
|
|
}
|
|
else
|
|
{
|
|
mCurRegionStats = new PerRegionStats(mRegionHandle);
|
|
}
|
|
|
|
// And add reference to map
|
|
mRegionStats[mRegionHandle] = mCurRegionStats;
|
|
|
|
// Start timestamp consistent with per-region collector
|
|
mResetTimestamp = mCurRegionStats->mStartTimestamp;
|
|
}
|
|
|
|
|
|
void
|
|
LLViewerAssetStats::setRegion(region_handle_t region_handle)
|
|
{
|
|
if (region_handle == mRegionHandle)
|
|
{
|
|
// Already active, ignore.
|
|
return;
|
|
}
|
|
|
|
// Get duration for current set
|
|
const duration_t now = LLViewerAssetStatsFF::get_timestamp();
|
|
mCurRegionStats->accumulateTime(now);
|
|
|
|
// Prepare new set
|
|
PerRegionContainer::iterator new_stats = mRegionStats.find(region_handle);
|
|
if (mRegionStats.end() == new_stats)
|
|
{
|
|
// Haven't seen this region_id before, create a new block and make it current.
|
|
mCurRegionStats = new PerRegionStats(region_handle);
|
|
mRegionStats[region_handle] = mCurRegionStats;
|
|
}
|
|
else
|
|
{
|
|
mCurRegionStats = new_stats->second;
|
|
}
|
|
mCurRegionStats->mStartTimestamp = now;
|
|
mRegionHandle = region_handle;
|
|
}
|
|
|
|
|
|
void
|
|
LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
|
{
|
|
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
|
|
|
|
++(mCurRegionStats->mRequests[int(eac)].mEnqueued);
|
|
}
|
|
|
|
void
|
|
LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
|
{
|
|
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
|
|
|
|
++(mCurRegionStats->mRequests[int(eac)].mDequeued);
|
|
}
|
|
|
|
void
|
|
LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration)
|
|
{
|
|
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
|
|
|
|
mCurRegionStats->mRequests[int(eac)].mResponse.record(duration);
|
|
}
|
|
|
|
void
|
|
LLViewerAssetStats::recordFPS(F32 fps)
|
|
{
|
|
mCurRegionStats->mFPS.record(fps);
|
|
}
|
|
|
|
LLSD
|
|
LLViewerAssetStats::asLLSD(bool compact_output)
|
|
{
|
|
// Top-level tags
|
|
static const LLSD::String tags[EVACCount] =
|
|
{
|
|
LLSD::String("get_texture_temp_http"),
|
|
LLSD::String("get_texture_temp_udp"),
|
|
LLSD::String("get_texture_non_temp_http"),
|
|
LLSD::String("get_texture_non_temp_udp"),
|
|
LLSD::String("get_wearable_udp"),
|
|
LLSD::String("get_sound_udp"),
|
|
LLSD::String("get_gesture_udp"),
|
|
LLSD::String("get_other")
|
|
};
|
|
|
|
// 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");
|
|
static const LLSD::String rmin_tag("resp_min");
|
|
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);
|
|
|
|
LLSD regions = LLSD::emptyArray();
|
|
for (PerRegionContainer::iterator it = mRegionStats.begin();
|
|
mRegionStats.end() != it;
|
|
++it)
|
|
{
|
|
if (0 == it->first)
|
|
{
|
|
// Never emit NULL UUID/handle in results.
|
|
continue;
|
|
}
|
|
|
|
PerRegionStats & stats = *it->second;
|
|
|
|
LLSD reg_stat = LLSD::emptyMap();
|
|
|
|
for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i)
|
|
{
|
|
PerRegionStats::prs_group & group(stats.mRequests[i]);
|
|
|
|
if ((! compact_output) ||
|
|
group.mEnqueued.getCount() ||
|
|
group.mDequeued.getCount() ||
|
|
group.mResponse.getCount())
|
|
{
|
|
LLSD & slot = reg_stat[tags[i]];
|
|
slot = LLSD::emptyMap();
|
|
slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
|
|
slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
|
|
slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
|
|
slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6));
|
|
slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6));
|
|
slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
|
|
}
|
|
}
|
|
|
|
if ((! compact_output) || stats.mFPS.getCount())
|
|
{
|
|
LLSD & slot = reg_stat["fps"];
|
|
slot = LLSD::emptyMap();
|
|
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()));
|
|
}
|
|
U32 grid_x(0), grid_y(0);
|
|
grid_from_region_handle(it->first, &grid_x, &grid_y);
|
|
reg_stat["grid_x"] = LLSD::Integer(grid_x);
|
|
reg_stat["grid_y"] = LLSD::Integer(grid_y);
|
|
reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
|
|
regions.append(reg_stat);
|
|
}
|
|
|
|
LLSD ret = LLSD::emptyMap();
|
|
ret["regions"] = regions;
|
|
ret["duration"] = LLSD::Real((now - mResetTimestamp) * 1.0e-6);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
LLViewerAssetStats::merge(const LLViewerAssetStats & src)
|
|
{
|
|
// mRegionHandle, mCurRegionStats and mResetTimestamp are left untouched.
|
|
// Just merge the stats bodies
|
|
|
|
const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
|
|
for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
|
|
{
|
|
PerRegionContainer::iterator dst(mRegionStats.find(it->first));
|
|
if (mRegionStats.end() == dst)
|
|
{
|
|
// Destination is missing data, just make a private copy
|
|
mRegionStats[it->first] = new PerRegionStats(*it->second);
|
|
}
|
|
else
|
|
{
|
|
dst->second->merge(*it->second);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// Global free-function definitions (LLViewerAssetStatsFF namespace)
|
|
// ------------------------------------------------------
|
|
|
|
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.
|
|
//
|
|
// As for the threads themselves... rather than do fine-grained
|
|
// locking as we gather statistics, this code creates a collector
|
|
// for each thread, allocated and run independently. Logging
|
|
// happens at relatively infrequent intervals and at that time
|
|
// the data is sent to a single thread to be aggregated into
|
|
// a single entity with locks, thread safety and other niceties.
|
|
//
|
|
// A particularly fussy implementation would distribute the
|
|
// per-thread pointers across separate cache lines. But that should
|
|
// be beyond current requirements.
|
|
//
|
|
|
|
// 'main' thread - initial program thread
|
|
|
|
void
|
|
set_region_main(LLViewerAssetStats::region_handle_t region_handle)
|
|
{
|
|
if (! gViewerAssetStatsMain)
|
|
return;
|
|
|
|
gViewerAssetStatsMain->setRegion(region_handle);
|
|
}
|
|
|
|
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, LLViewerAssetStats::duration_t duration)
|
|
{
|
|
if (! gViewerAssetStatsMain)
|
|
return;
|
|
|
|
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
|
|
|
|
void
|
|
set_region_thread1(LLViewerAssetStats::region_handle_t region_handle)
|
|
{
|
|
if (! gViewerAssetStatsThread1)
|
|
return;
|
|
|
|
gViewerAssetStatsThread1->setRegion(region_handle);
|
|
}
|
|
|
|
void
|
|
record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
|
{
|
|
if (! gViewerAssetStatsThread1)
|
|
return;
|
|
|
|
gViewerAssetStatsThread1->recordGetEnqueued(at, with_http, is_temp);
|
|
}
|
|
|
|
void
|
|
record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
|
{
|
|
if (! gViewerAssetStatsThread1)
|
|
return;
|
|
|
|
gViewerAssetStatsThread1->recordGetDequeued(at, with_http, is_temp);
|
|
}
|
|
|
|
void
|
|
record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
|
|
{
|
|
if (! gViewerAssetStatsThread1)
|
|
return;
|
|
|
|
gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration);
|
|
}
|
|
|
|
|
|
void
|
|
init()
|
|
{
|
|
if (! gViewerAssetStatsMain)
|
|
{
|
|
gViewerAssetStatsMain = new LLViewerAssetStats();
|
|
}
|
|
if (! gViewerAssetStatsThread1)
|
|
{
|
|
gViewerAssetStatsThread1 = new LLViewerAssetStats();
|
|
}
|
|
}
|
|
|
|
void
|
|
cleanup()
|
|
{
|
|
delete gViewerAssetStatsMain;
|
|
gViewerAssetStatsMain = 0;
|
|
|
|
delete gViewerAssetStatsThread1;
|
|
gViewerAssetStatsThread1 = 0;
|
|
}
|
|
|
|
|
|
} // namespace LLViewerAssetStatsFF
|
|
|
|
|
|
// ------------------------------------------------------
|
|
// Local function definitions
|
|
// ------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
|
|
LLViewerAssetStats::EViewerAssetCategories
|
|
asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp)
|
|
{
|
|
// For statistical purposes, we divide GETs into several
|
|
// populations of asset fetches:
|
|
// - textures which are de-prioritized in the asset system
|
|
// - wearables (clothing, bodyparts) which directly affect
|
|
// user experiences when they log in
|
|
// - sounds
|
|
// - gestures
|
|
// - everything else.
|
|
//
|
|
llassert_always(50 == LLViewerAssetType::AT_COUNT);
|
|
|
|
// Multiple asset definitions are floating around so this requires some
|
|
// maintenance and attention.
|
|
static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] =
|
|
{
|
|
LLViewerAssetStats::EVACTextureTempHTTPGet, // (0) AT_TEXTURE
|
|
LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND
|
|
LLViewerAssetStats::EVACOtherGet, // AT_CALLINGCARD
|
|
LLViewerAssetStats::EVACOtherGet, // AT_LANDMARK
|
|
LLViewerAssetStats::EVACOtherGet, // AT_SCRIPT
|
|
LLViewerAssetStats::EVACWearableUDPGet, // AT_CLOTHING
|
|
LLViewerAssetStats::EVACOtherGet, // AT_OBJECT
|
|
LLViewerAssetStats::EVACOtherGet, // AT_NOTECARD
|
|
LLViewerAssetStats::EVACOtherGet, // AT_CATEGORY
|
|
LLViewerAssetStats::EVACOtherGet, // AT_ROOT_CATEGORY
|
|
LLViewerAssetStats::EVACOtherGet, // (10) AT_LSL_TEXT
|
|
LLViewerAssetStats::EVACOtherGet, // AT_LSL_BYTECODE
|
|
LLViewerAssetStats::EVACOtherGet, // AT_TEXTURE_TGA
|
|
LLViewerAssetStats::EVACWearableUDPGet, // AT_BODYPART
|
|
LLViewerAssetStats::EVACOtherGet, // AT_TRASH
|
|
LLViewerAssetStats::EVACOtherGet, // AT_SNAPSHOT_CATEGORY
|
|
LLViewerAssetStats::EVACOtherGet, // AT_LOST_AND_FOUND
|
|
LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND_WAV
|
|
LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_TGA
|
|
LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_JPEG
|
|
LLViewerAssetStats::EVACGestureUDPGet, // (20) AT_ANIMATION
|
|
LLViewerAssetStats::EVACGestureUDPGet, // AT_GESTURE
|
|
LLViewerAssetStats::EVACOtherGet, // AT_SIMSTATE
|
|
LLViewerAssetStats::EVACOtherGet, // AT_FAVORITE
|
|
LLViewerAssetStats::EVACOtherGet, // AT_LINK
|
|
LLViewerAssetStats::EVACOtherGet, // AT_LINK_FOLDER
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, // (30)
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, // (40)
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, //
|
|
LLViewerAssetStats::EVACOtherGet, // AT_MESH
|
|
// (50)
|
|
};
|
|
|
|
if (at < 0 || at >= LLViewerAssetType::AT_COUNT)
|
|
{
|
|
return LLViewerAssetStats::EVACOtherGet;
|
|
}
|
|
LLViewerAssetStats::EViewerAssetCategories ret(asset_to_bin_map[at]);
|
|
if (LLViewerAssetStats::EVACTextureTempHTTPGet == ret)
|
|
{
|
|
// Indexed with [is_temp][with_http]
|
|
static const LLViewerAssetStats::EViewerAssetCategories texture_bin_map[2][2] =
|
|
{
|
|
{
|
|
LLViewerAssetStats::EVACTextureNonTempUDPGet,
|
|
LLViewerAssetStats::EVACTextureNonTempHTTPGet,
|
|
},
|
|
{
|
|
LLViewerAssetStats::EVACTextureTempUDPGet,
|
|
LLViewerAssetStats::EVACTextureTempHTTPGet,
|
|
}
|
|
};
|
|
|
|
ret = texture_bin_map[is_temp][with_http];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} // anonymous namespace
|