Merged in lindenlab/viewer-release

master
AndreyL ProductEngine 2017-06-20 23:16:03 +03:00
commit 270cd8ff15
24 changed files with 1999 additions and 2003 deletions

View File

@ -527,3 +527,4 @@ cea1632c002c065985ebea15eeeb4aac90f50545 5.0.2-release
02c24e9f4f7d8aa0de75f27817dda098582f4936 5.0.3-release
022709ef76a331cac1ba6ef1a6da8a5e9ef63f5a 5.0.4-release
b4d76b5590fdf8bab72c64442353753a527cbc44 5.0.5-release
3e5035dfd8af49bd4c0009f0a76ef46a15991a45 5.0.6-release

View File

@ -1305,6 +1305,7 @@ Sovereign Engineer
MAINT-6913
STORM-2143
STORM-2148
MAINT-7343
SpacedOut Frye
VWR-34
VWR-45

View File

@ -152,7 +152,7 @@ public:
static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
static const std::string& badLookup(); // error string when a lookup fails
protected:

View File

@ -572,7 +572,7 @@ namespace LLError
mFunctionString += std::string(mFunction) + ":";
for (size_t i = 0; i < mTagCount; i++)
{
mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? "" : ",");
mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? " " : ",");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -138,6 +138,7 @@ public:
BOOL mIsUserWaiting; // We don't want to try forever if a user is waiting for a result.
F64Seconds mTimeout; // Amount of time before timing out.
LLUUID mRequestingAgentID; // Only valid for uploads from an agent
F64 mBytesFetched;
virtual LLSD getTerseDetails() const;
virtual LLSD getFullDetails() const;
@ -186,18 +187,9 @@ typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
// we can use bind and remove the userData parameter.
//
typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id,
LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status);
LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status);
class LLTempAssetStorage
{
public:
virtual ~LLTempAssetStorage() =0;
virtual void addTempAssetData(const LLUUID& asset_id,
const LLUUID& agent_id,
const std::string& host_name) = 0;
};
class LLAssetStorage : public LLTempAssetStorage
class LLAssetStorage
{
public:
// VFS member is public because static child methods need it :(
@ -240,12 +232,11 @@ public:
void setUpstream(const LLHost &upstream_host);
virtual BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type);
BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type);
// public interface methods
// note that your callback may get called BEFORE the function returns
virtual void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE);
void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE);
/*
* TransactionID version
@ -260,25 +251,11 @@ public:
bool is_priority = false,
bool store_local = false,
bool user_waiting= false,
F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0;
/*
* AssetID version
* Sim needs both store_local and requesting_agent_id.
*/
virtual void storeAssetData(
const LLUUID& asset_id,
LLAssetType::EType asset_type,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file = false,
bool is_priority = false,
bool store_local = false,
const LLUUID& requesting_agent_id = LLUUID::null,
bool user_waiting= false,
F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
virtual void checkForTimeouts();
virtual void logAssetStorageInfo() = 0;
void checkForTimeouts();
void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype,
@ -303,17 +280,17 @@ protected:
bool findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
LLGetAssetCallback callback, void *user_data);
virtual LLSD getPendingDetailsImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
LLSD getPendingDetailsImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
virtual LLSD getPendingRequestImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
LLSD getPendingRequestImpl(const request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
virtual bool deletePendingRequestImpl(request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
bool deletePendingRequestImpl(request_list_t* requests,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
public:
static const LLAssetRequest* findRequest(const request_list_t* requests,
@ -332,19 +309,23 @@ public:
S32 getNumPendingLocalUploads();
S32 getNumPending(ERequestType rt) const;
virtual LLSD getPendingDetails(ERequestType rt,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
LLSD getPendingDetails(ERequestType rt,
LLAssetType::EType asset_type,
const std::string& detail_prefix) const;
virtual LLSD getPendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
LLSD getPendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id) const;
virtual bool deletePendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
bool deletePendingRequest(ERequestType rt,
LLAssetType::EType asset_type,
const LLUUID& asset_id);
static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
const LLUUID& callback_id, LLAssetType::EType callback_type,
S32 result_code, LLExtStat ext_status);
// download process callbacks
static void downloadCompleteCallback(
S32 result,
@ -370,22 +351,9 @@ public:
static const char* getErrorString( S32 status );
// deprecated file-based methods
// Not overriden
void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority = FALSE);
/*
* AssetID version.
*/
virtual void storeAssetData(
const std::string& filename,
const LLUUID& asset_id,
LLAssetType::EType type,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file = false,
bool is_priority = false,
bool user_waiting = false,
F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT);
/*
* TransactionID version
*/
@ -398,23 +366,11 @@ public:
bool temp_file = false,
bool is_priority = false,
bool user_waiting = false,
F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT);
F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0;
static void legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status);
static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status);
// Temp assets are stored on sim nodes, they have agent ID and location data associated with them.
// This is a no-op for non-http asset systems
virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name);
virtual BOOL hasTempAssetData(const LLUUID& texture_id) const;
virtual std::string getTempAssetHostName(const LLUUID& texture_id) const;
virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const;
virtual void removeTempAssetData(const LLUUID& asset_id);
virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id);
// Pass LLUUID::null for all
virtual void dumpTempAssetData(const LLUUID& avatar_id) const;
virtual void clearTempAssetData();
// add extra methods to handle metadata
protected:
@ -424,7 +380,7 @@ protected:
virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
void *user_data, BOOL duplicate,
BOOL is_priority);
BOOL is_priority) = 0;
private:
void _init(LLMessageSystem *msg,

View File

@ -1 +1 @@
5.0.6
5.0.7

View File

@ -14705,6 +14705,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>AssetStorageLogFrequency</key>
<map>
<key>Comment</key>
<string>Seconds between display of AssetStorage info in log (0 for never)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>60.0</real>
</map>
<key>LogWearableAssetSave</key>
<map>
<key>Comment</key>
@ -14778,6 +14789,15 @@
<key>Value</key>
<real>1</real>
</map>
<key>PoolSizeAssetStorage</key>
<map>
<key>Comment</key>
<string>Coroutine Pool size for AssetStorage requests</string>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>12</real>
</map>
<!-- Settings below are for back compatibility only.
They are not used in current viewer anymore. But they can't be removed to avoid

View File

@ -844,12 +844,6 @@ bool LLAppViewer::init()
LLMachineID::init();
{
// Viewer metrics initialization
//static LLCachedControl<bool> metrics_submode(gSavedSettings,
// "QAModeMetrics",
// false,
// "Enables QA features (logging, faster cycling) for metrics collector");
if (gSavedSettings.getBOOL("QAModeMetrics"))
{
app_metrics_qa_mode = true;
@ -5928,23 +5922,14 @@ void LLAppViewer::metricsSend(bool enable_reporting)
{
std::string caps_url = regionp->getCapability("ViewerMetrics");
if (gSavedSettings.getBOOL("QAModeMetrics"))
{
dump_sequential_xml("metric_asset_stats",gViewerAssetStats->asLLSD(true));
}
// Make a copy of the main stats to send into another thread.
// Receiving thread takes ownership.
LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStats));
main_stats->stop();
LLSD sd = gViewerAssetStats->asLLSD(true);
// Send a report request into 'thread1' to get the rest of the data
// and provide some additional parameters while here.
LLAppViewer::sTextureFetch->commandSendMetrics(caps_url,
gAgentSessionID,
gAgentID,
main_stats);
main_stats = 0; // Ownership transferred
sd);
}
else
{

View File

@ -343,10 +343,6 @@ LLMeshRepository gMeshRepo;
const S32 MESH_HEADER_SIZE = 4096; // Important: assumption is that headers fit in this space
const S32 REQUEST_HIGH_WATER_MIN = 32; // Limits for GetMesh regions
const S32 REQUEST_HIGH_WATER_MAX = 150; // Should remain under 2X throttle
const S32 REQUEST_LOW_WATER_MIN = 16;
const S32 REQUEST_LOW_WATER_MAX = 75;
const S32 REQUEST2_HIGH_WATER_MIN = 32; // Limits for GetMesh2 regions
const S32 REQUEST2_HIGH_WATER_MAX = 100;
@ -808,10 +804,8 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargeOptions(),
mHttpHeaders(),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpPriority(0),
mGetMeshVersion(2)
mHttpPriority(0)
{
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
@ -828,7 +822,6 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_VND_LL_MESH);
mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH2);
mHttpLegacyPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH1);
mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
}
@ -1103,13 +1096,9 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
}
// Mutex: must be holding mMutex when called
void LLMeshRepoThread::setGetMeshCaps(const std::string & get_mesh1,
const std::string & get_mesh2,
int pref_version)
void LLMeshRepoThread::setGetMeshCap(const std::string & mesh_cap)
{
mGetMeshCapability = get_mesh1;
mGetMesh2Capability = get_mesh2;
mGetMeshVersion = pref_version;
mGetMeshCapability = mesh_cap;
}
@ -1117,29 +1106,14 @@ void LLMeshRepoThread::setGetMeshCaps(const std::string & get_mesh1,
// over a GetMesh cap.
//
// Mutex: acquires mMutex
void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * version)
void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url)
{
std::string res_url;
int res_version(2);
if (gAgent.getRegion())
{
LLMutexLock lock(mMutex);
// Get a consistent pair of (cap string, version). The
// locking could be eliminated here without loss of safety
// by using a set of staging values in setGetMeshCaps().
if (! mGetMesh2Capability.empty() && mGetMeshVersion > 1)
{
res_url = mGetMesh2Capability;
res_version = 2;
}
else
{
res_url = mGetMeshCapability;
res_version = 1;
}
res_url = mGetMeshCapability;
}
if (! res_url.empty())
@ -1149,19 +1123,15 @@ void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * ver
}
else
{
LL_WARNS_ONCE(LOG_MESH) << "Current region does not have GetMesh capability! Cannot load "
LL_WARNS_ONCE(LOG_MESH) << "Current region does not have ViewerAsset capability! Cannot load "
<< mesh_id << ".mesh" << LL_ENDL;
}
*url = res_url;
*version = res_version;
}
// Issue an HTTP GET request with byte range using the right
// policy class. Large requests go to the large request class.
// If the current region supports GetMesh2, we prefer that for
// smaller requests otherwise we try to use the traditional
// GetMesh capability and connection concurrency.
// policy class.
//
// @return Valid handle or LLCORE_HTTP_HANDLE_INVALID.
// If the latter, actual status is found in
@ -1169,7 +1139,7 @@ void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * ver
// next call to this method.
//
// Thread: repo
LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int cap_version,
LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url,
size_t offset, size_t len,
const LLCore::HttpHandler::ptr_t &handler)
{
@ -1180,16 +1150,14 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c
if (len < LARGE_MESH_FETCH_THRESHOLD)
{
handle = mHttpRequest->requestGetByteRange((2 == cap_version
? mHttpPolicyClass
: mHttpLegacyPolicyClass),
mHttpPriority,
url,
(disable_range_req ? size_t(0) : offset),
(disable_range_req ? size_t(0) : len),
mHttpOptions,
mHttpHeaders,
handler);
handle = mHttpRequest->requestGetByteRange( mHttpPolicyClass,
mHttpPriority,
url,
(disable_range_req ? size_t(0) : offset),
(disable_range_req ? size_t(0) : len),
mHttpOptions,
mHttpHeaders,
handler);
if (LLCORE_HTTP_HANDLE_INVALID != handle)
{
++LLMeshRepository::sHTTPRequestCount;
@ -1279,14 +1247,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
}
//reading from VFS failed for whatever reason, fetch from sim
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
constructUrl(mesh_id, &http_url);
if (!http_url.empty())
{
LLMeshHandlerBase::ptr_t handler(new LLMeshSkinInfoHandler(mesh_id, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID
@ -1372,14 +1339,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
}
//reading from VFS failed for whatever reason, fetch from sim
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
constructUrl(mesh_id, &http_url);
if (!http_url.empty())
{
LLMeshHandlerBase::ptr_t handler(new LLMeshDecompositionHandler(mesh_id, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID
@ -1464,14 +1430,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
}
//reading from VFS failed for whatever reason, fetch from sim
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
constructUrl(mesh_id, &http_url);
if (!http_url.empty())
{
LLMeshHandlerBase::ptr_t handler(new LLMeshPhysicsShapeHandler(mesh_id, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
LL_WARNS(LOG_MESH) << "HTTP GET request failed for physics shape on mesh " << mID
@ -1558,9 +1523,8 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
//either cache entry doesn't exist or is corrupt, request header from simulator
bool retval = true;
int cap_version(2);
std::string http_url;
constructUrl(mesh_params.getSculptID(), &http_url, &cap_version);
constructUrl(mesh_params.getSculptID(), &http_url);
if (!http_url.empty())
{
@ -1569,7 +1533,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
//NOTE -- this will break of headers ever exceed 4KB
LLMeshHandlerBase::ptr_t handler(new LLMeshHeaderHandler(mesh_params, 0, MESH_HEADER_SIZE));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, 0, MESH_HEADER_SIZE, handler);
LLCore::HttpHandle handle = getByteRange(http_url, 0, MESH_HEADER_SIZE, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
LL_WARNS(LOG_MESH) << "HTTP GET request failed for mesh header " << mID
@ -1645,14 +1609,13 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
}
//reading from VFS failed for whatever reason, fetch from sim
int cap_version(2);
std::string http_url;
constructUrl(mesh_id, &http_url, &cap_version);
constructUrl(mesh_id, &http_url);
if (!http_url.empty())
{
LLMeshHandlerBase::ptr_t handler(new LLMeshLODHandler(mesh_params, lod, offset, size));
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler);
if (LLCORE_HTTP_HANDLE_INVALID == handle)
{
LL_WARNS(LOG_MESH) << "HTTP GET request failed for LOD on mesh " << mID
@ -3292,8 +3255,7 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S3
LLMeshRepository::LLMeshRepository()
: mMeshMutex(NULL),
mMeshThreadCount(0),
mThread(NULL),
mGetMeshVersion(2)
mThread(NULL)
{
}
@ -3476,35 +3438,21 @@ void LLMeshRepository::notifyLoadedMeshes()
{ //called from main thread
LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH);
if (1 == mGetMeshVersion)
{
// Legacy GetMesh operation with high connection concurrency
LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests");
LLMeshRepoThread::sRequestHighWater = llclamp(2 * S32(LLMeshRepoThread::sMaxConcurrentRequests),
REQUEST_HIGH_WATER_MIN,
REQUEST_HIGH_WATER_MAX);
LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2,
REQUEST_LOW_WATER_MIN,
REQUEST_LOW_WATER_MAX);
}
else
{
// GetMesh2 operation with keepalives, etc. With pipelining,
// we'll increase this. See llappcorehttp and llcorehttp for
// discussion on connection strategies.
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
S32 scale(app_core_http.isPipelined(LLAppCoreHttp::AP_MESH2)
? (2 * LLAppCoreHttp::PIPELINING_DEPTH)
: 5);
// GetMesh2 operation with keepalives, etc. With pipelining,
// we'll increase this. See llappcorehttp and llcorehttp for
// discussion on connection strategies.
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
S32 scale(app_core_http.isPipelined(LLAppCoreHttp::AP_MESH2)
? (2 * LLAppCoreHttp::PIPELINING_DEPTH)
: 5);
LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("Mesh2MaxConcurrentRequests");
LLMeshRepoThread::sRequestHighWater = llclamp(scale * S32(LLMeshRepoThread::sMaxConcurrentRequests),
REQUEST2_HIGH_WATER_MIN,
REQUEST2_HIGH_WATER_MAX);
LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2,
REQUEST2_LOW_WATER_MIN,
REQUEST2_LOW_WATER_MAX);
}
LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("Mesh2MaxConcurrentRequests");
LLMeshRepoThread::sRequestHighWater = llclamp(scale * S32(LLMeshRepoThread::sMaxConcurrentRequests),
REQUEST2_HIGH_WATER_MIN,
REQUEST2_HIGH_WATER_MAX);
LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2,
REQUEST2_LOW_WATER_MIN,
REQUEST2_LOW_WATER_MAX);
//clean up completed upload threads
for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )
@ -3610,15 +3558,10 @@ void LLMeshRepository::notifyLoadedMeshes()
if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
{
region_name = gAgent.getRegion()->getName();
const bool use_v1(gSavedSettings.getBOOL("MeshUseGetMesh1"));
const std::string mesh1(gAgent.getRegion()->getCapability("GetMesh"));
const std::string mesh2(gAgent.getRegion()->getCapability("GetMesh2"));
mGetMeshVersion = (mesh2.empty() || use_v1) ? 1 : 2;
mThread->setGetMeshCaps(mesh1, mesh2, mGetMeshVersion);
const std::string mesh_cap(gAgent.getRegion()->getViewerAssetUrl());
mThread->setGetMeshCap(mesh_cap);
LL_DEBUGS(LOG_MESH) << "Retrieving caps for region '" << region_name
<< "', GetMesh2: " << mesh2
<< ", GetMesh: " << mesh1
<< ", using version: " << mGetMeshVersion
<< "', ViewerAsset cap: " << mesh_cap
<< LL_ENDL;
}
}

View File

@ -279,7 +279,6 @@ public:
LLCore::HttpOptions::ptr_t mHttpLargeOptions;
LLCore::HttpHeaders::ptr_t mHttpHeaders;
LLCore::HttpRequest::policy_t mHttpPolicyClass;
LLCore::HttpRequest::policy_t mHttpLegacyPolicyClass;
LLCore::HttpRequest::policy_t mHttpLargePolicyClass;
LLCore::HttpRequest::priority_t mHttpPriority;
@ -287,8 +286,6 @@ public:
http_request_set mHttpRequestSet; // Outstanding HTTP requests
std::string mGetMeshCapability;
std::string mGetMesh2Capability;
int mGetMeshVersion;
LLMeshRepoThread();
~LLMeshRepoThread();
@ -335,12 +332,10 @@ public:
// mesh fetch URLs.
//
// Mutex: must be holding mMutex when called
void setGetMeshCaps(const std::string & get_mesh1,
const std::string & get_mesh2,
int pref_version);
void setGetMeshCap(const std::string & get_mesh);
// Mutex: acquires mMutex
void constructUrl(LLUUID mesh_id, std::string * url, int * version);
void constructUrl(LLUUID mesh_id, std::string * url);
private:
// Issue a GET request to a URL with 'Range' header using
@ -349,7 +344,7 @@ private:
// or dispose of handler.
//
// Threads: Repo thread only
LLCore::HttpHandle getByteRange(const std::string & url, int cap_version,
LLCore::HttpHandle getByteRange(const std::string & url,
size_t offset, size_t len,
const LLCore::HttpHandler::ptr_t &handler);
};
@ -585,8 +580,6 @@ public:
void uploadError(LLSD& args);
void updateInventory(inventory_data data);
int mGetMeshVersion; // Shadows value in LLMeshRepoThread
};
extern LLMeshRepository gMeshRepo;

View File

@ -30,8 +30,6 @@
#include <map>
#include <algorithm>
#include "llstl.h"
#include "lltexturefetch.h"
#include "lldir.h"
@ -485,7 +483,7 @@ private:
void recordTextureStart(bool is_http);
// Threads: Ttf
void recordTextureDone(bool is_http);
void recordTextureDone(bool is_http, F64 byte_count);
void lockWorkMutex() { mWorkMutex.lock(); }
void unlockWorkMutex() { mWorkMutex.unlock(); }
@ -824,7 +822,7 @@ public:
TFReqSendMetrics(const std::string & caps_url,
const LLUUID & session_id,
const LLUUID & agent_id,
LLViewerAssetStats * main_stats);
LLSD& stats_sd);
TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined
virtual ~TFReqSendMetrics();
@ -835,7 +833,7 @@ public:
const std::string mCapsURL;
const LLUUID mSessionID;
const LLUUID mAgentID;
LLViewerAssetStats * mMainStats;
LLSD mStatsSD;
private:
LLCore::HttpHandler::ptr_t mHandler;
@ -1351,7 +1349,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (region)
{
std::string http_url = region->getHttpUrl() ;
std::string http_url = region->getViewerAssetUrl();
if (!http_url.empty())
{
if (mFTType != FTT_DEFAULT)
@ -1426,6 +1424,20 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
if (processSimulatorPackets())
{
// Capture some measure of total size for metrics
F64 byte_count = 0;
if (mLastPacket >= mFirstPacket)
{
for (S32 i=mFirstPacket; i<=mLastPacket; i++)
{
llassert_always((i>=0) && (i<mPackets.size()));
if (mPackets[i])
{
byte_count += mPackets[i]->mSize;
}
}
}
LL_DEBUGS(LOG_TXT) << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL;
mFetcher->removeFromNetworkQueue(this, false);
if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
@ -1443,7 +1455,8 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
setState(DECODE_IMAGE);
mWriteToCacheState = SHOULD_WRITE;
recordTextureDone(false);
recordTextureDone(false, byte_count);
}
else
{
@ -2093,7 +2106,7 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe
mFetcher->removeFromHTTPQueue(mID, data_size);
recordTextureDone(true);
recordTextureDone(true, data_size);
} // -Mw
@ -2222,6 +2235,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()
S32 buffer_size = mFormattedImage->getDataSize();
for (S32 i = mFirstPacket; i<=mLastPacket; i++)
{
llassert_always((i>=0) && (i<mPackets.size()));
llassert_always(mPackets[i]);
buffer_size += mPackets[i]->mSize;
}
@ -2493,14 +2507,15 @@ void LLTextureFetchWorker::recordTextureStart(bool is_http)
// Threads: Ttf
void LLTextureFetchWorker::recordTextureDone(bool is_http)
void LLTextureFetchWorker::recordTextureDone(bool is_http, F64 byte_count)
{
if (mMetricsStartTime.value())
{
LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_TEXTURE,
is_http,
LLImageBase::TYPE_AVATAR_BAKE == mType,
LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
is_http,
LLImageBase::TYPE_AVATAR_BAKE == mType,
LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime,
byte_count);
mMetricsStartTime = (U32Seconds)0;
}
LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE,
@ -3863,9 +3878,9 @@ void LLTextureFetch::commandSetRegion(U64 region_handle)
void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
const LLUUID & session_id,
const LLUUID & agent_id,
LLViewerAssetStats * main_stats)
LLSD& stats_sd)
{
TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, stats_sd);
cmdEnqueue(req);
}
@ -3974,22 +3989,20 @@ TFReqSetRegion::doWork(LLTextureFetch *)
}
TFReqSendMetrics::TFReqSendMetrics(const std::string & caps_url,
const LLUUID & session_id,
const LLUUID & agent_id,
LLViewerAssetStats * main_stats):
const LLUUID & session_id,
const LLUUID & agent_id,
LLSD& stats_sd):
LLTextureFetch::TFRequest(),
mCapsURL(caps_url),
mSessionID(session_id),
mAgentID(agent_id),
mMainStats(main_stats),
mStatsSD(stats_sd),
mHandler(new AssetReportHandler)
{}
TFReqSendMetrics::~TFReqSendMetrics()
{
delete mMainStats;
mMainStats = 0;
}
@ -4010,26 +4023,19 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
static volatile bool reporting_started(false);
static volatile S32 report_sequence(0);
// 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;
LLViewerAssetStats::AssetStats stats;
main_stats.getStats(stats, true);
//LLSD merged_llsd = main_stats.asLLSD();
// In mStatsSD, we have a copy we own of the LLSD representation
// of the asset stats. Add some additional fields and ship it off.
static const S32 metrics_data_version = 2;
bool initial_report = !reporting_started;
stats.session_id = mSessionID;
stats.agent_id = mAgentID;
stats.message = "ViewerAssetMetrics";
stats.sequence = static_cast<bool>(report_sequence);
stats.initial = initial_report;
stats.break_ = static_cast<bool>(LLTextureFetch::svMetricsDataBreak);
LLSD sd;
LLParamSDParser parser;
parser.writeSD(sd, stats);
mStatsSD["session_id"] = mSessionID;
mStatsSD["agent_id"] = mAgentID;
mStatsSD["message"] = "ViewerAssetMetrics";
mStatsSD["sequence"] = report_sequence;
mStatsSD["initial"] = initial_report;
mStatsSD["version"] = metrics_data_version;
mStatsSD["break"] = static_cast<bool>(LLTextureFetch::svMetricsDataBreak);
// Update sequence number
if (S32_MAX == ++report_sequence)
@ -4040,8 +4046,13 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
// Limit the size of the stats report if necessary.
sd["truncated"] = truncate_viewer_metrics(10, sd);
mStatsSD["truncated"] = truncate_viewer_metrics(10, mStatsSD);
if (gSavedSettings.getBOOL("QAModeMetrics"))
{
dump_sequential_xml("metric_asset_stats",mStatsSD);
}
if (! mCapsURL.empty())
{
// Don't care about handle, this is a fire-and-forget operation.
@ -4049,7 +4060,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
fetcher->getMetricsPolicyClass(),
report_priority,
mCapsURL,
sd,
mStatsSD,
LLCore::HttpOptions::ptr_t(),
fetcher->getMetricsHeaders(),
mHandler);
@ -4063,7 +4074,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
// In QA mode, Metrics submode, log the result for ease of testing
if (fetcher->isQAMode())
{
LL_INFOS(LOG_TXT) << ll_pretty_print_sd(sd) << LL_ENDL;
LL_INFOS(LOG_TXT) << "ViewerAssetMetrics as submitted\n" << ll_pretty_print_sd(mStatsSD) << LL_ENDL;
}
return true;
@ -4580,7 +4591,7 @@ void LLTextureFetchDebugger::debugHTTP()
return;
}
mHTTPUrl = region->getHttpUrl();
mHTTPUrl = region->getViewerAssetUrl();
if (mHTTPUrl.empty())
{
LL_INFOS(LOG_TXT) << "Fetch Debugger : Current region URL undefined. Cannot fetch textures through HTTP." << LL_ENDL;

View File

@ -160,7 +160,7 @@ public:
void commandSendMetrics(const std::string & caps_url,
const LLUUID & session_id,
const LLUUID & agent_id,
LLViewerAssetStats * main_stats);
LLSD& stats_sd);
// Threads: T*
void commandDataBreak();

View File

@ -80,6 +80,47 @@
*
*/
namespace LLTrace
{
// This little bit of shimmery is to allow the creation of
// default-constructed stat and event handles so we can make arrays of
// the things.
// The only sensible way to use this function is to immediately make a
// copy of the contents, since it always returns the same pointer.
const char *makeNewAutoName()
{
static char name[64];
static S32 auto_namer_number = 0;
snprintf(name,64,"auto_name_%d",auto_namer_number);
auto_namer_number++;
return name;
}
template <typename T = F64>
class DCCountStatHandle:
public CountStatHandle<T>
{
public:
DCCountStatHandle(const char *name = makeNewAutoName(), const char *description=NULL):
CountStatHandle<T>(name,description)
{
}
};
template <typename T = F64>
class DCEventStatHandle:
public EventStatHandle<T>
{
public:
DCEventStatHandle(const char *name = makeNewAutoName(), const char *description=NULL):
EventStatHandle<T>(name,description)
{
}
};
}
namespace LLViewerAssetStatsFF
{
static EViewerAssetCategories asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp)
@ -90,176 +131,45 @@ namespace LLViewerAssetStatsFF
// - wearables (clothing, bodyparts) which directly affect
// user experiences when they log in
// - sounds
// - gestures
// - gestures, including animations
// - everything else.
//
llassert_always(50 == LLViewerAssetType::AT_COUNT);
// Multiple asset definitions are floating around so this requires some
// maintenance and attention.
static const EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] =
{
EVACTextureTempHTTPGet, // (0) AT_TEXTURE
EVACSoundUDPGet, // AT_SOUND
EVACOtherGet, // AT_CALLINGCARD
EVACOtherGet, // AT_LANDMARK
EVACOtherGet, // AT_SCRIPT
EVACWearableUDPGet, // AT_CLOTHING
EVACOtherGet, // AT_OBJECT
EVACOtherGet, // AT_NOTECARD
EVACOtherGet, // AT_CATEGORY
EVACOtherGet, // AT_ROOT_CATEGORY
EVACOtherGet, // (10) AT_LSL_TEXT
EVACOtherGet, // AT_LSL_BYTECODE
EVACOtherGet, // AT_TEXTURE_TGA
EVACWearableUDPGet, // AT_BODYPART
EVACOtherGet, // AT_TRASH
EVACOtherGet, // AT_SNAPSHOT_CATEGORY
EVACOtherGet, // AT_LOST_AND_FOUND
EVACSoundUDPGet, // AT_SOUND_WAV
EVACOtherGet, // AT_IMAGE_TGA
EVACOtherGet, // AT_IMAGE_JPEG
EVACGestureUDPGet, // (20) AT_ANIMATION
EVACGestureUDPGet, // AT_GESTURE
EVACOtherGet, // AT_SIMSTATE
EVACOtherGet, // AT_FAVORITE
EVACOtherGet, // AT_LINK
EVACOtherGet, // AT_LINK_FOLDER
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, // (30)
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, // (40)
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, //
EVACOtherGet, // AT_MESH
// (50)
};
if (at < 0 || at >= LLViewerAssetType::AT_COUNT)
{
return EVACOtherGet;
}
EViewerAssetCategories ret(asset_to_bin_map[at]);
if (EVACTextureTempHTTPGet == ret)
{
// Indexed with [is_temp][with_http]
static const EViewerAssetCategories texture_bin_map[2][2] =
{
{
EVACTextureNonTempUDPGet,
EVACTextureNonTempHTTPGet,
},
{
EVACTextureTempUDPGet,
EVACTextureTempHTTPGet,
}
};
ret = texture_bin_map[is_temp][with_http];
}
EViewerAssetCategories ret;
switch (at)
{
case LLAssetType::AT_TEXTURE:
if (is_temp)
ret = with_http ? EVACTextureTempHTTPGet : EVACTextureTempUDPGet;
else
ret = with_http ? EVACTextureNonTempHTTPGet : EVACTextureNonTempUDPGet;
break;
case LLAssetType::AT_SOUND:
case LLAssetType::AT_SOUND_WAV:
ret = with_http ? EVACSoundHTTPGet : EVACSoundUDPGet;
break;
case LLAssetType::AT_CLOTHING:
case LLAssetType::AT_BODYPART:
ret = with_http ? EVACWearableHTTPGet : EVACWearableUDPGet;
break;
case LLAssetType::AT_ANIMATION:
case LLAssetType::AT_GESTURE:
ret = with_http ? EVACGestureHTTPGet : EVACGestureUDPGet;
break;
case LLAssetType::AT_LANDMARK:
ret = with_http ? EVACLandmarkHTTPGet : EVACLandmarkUDPGet;
break;
default:
ret = with_http ? EVACOtherHTTPGet : EVACOtherUDPGet;
break;
}
return ret;
}
static LLTrace::CountStatHandle<> sEnqueueAssetRequestsTempTextureHTTP ("enqueuedassetrequeststemptexturehttp",
"Number of temporary texture asset http requests enqueued"),
sEnqueueAssetRequestsTempTextureUDP ("enqueuedassetrequeststemptextureudp",
"Number of temporary texture asset udp requests enqueued"),
sEnqueueAssetRequestsNonTempTextureHTTP("enqueuedassetrequestsnontemptexturehttp",
"Number of texture asset http requests enqueued"),
sEnqueueAssetRequestsNonTempTextureUDP ("enqueuedassetrequestsnontemptextureudp",
"Number of texture asset udp requests enqueued"),
sEnqueuedAssetRequestsWearableUdp ("enqueuedassetrequestswearableudp",
"Number of wearable asset requests enqueued"),
sEnqueuedAssetRequestsSoundUdp ("enqueuedassetrequestssoundudp",
"Number of sound asset requests enqueued"),
sEnqueuedAssetRequestsGestureUdp ("enqueuedassetrequestsgestureudp",
"Number of gesture asset requests enqueued"),
sEnqueuedAssetRequestsOther ("enqueuedassetrequestsother",
"Number of other asset requests enqueued");
static LLTrace::CountStatHandle<>* sEnqueued[EVACCount] = {
&sEnqueueAssetRequestsTempTextureHTTP,
&sEnqueueAssetRequestsTempTextureUDP,
&sEnqueueAssetRequestsNonTempTextureHTTP,
&sEnqueueAssetRequestsNonTempTextureUDP,
&sEnqueuedAssetRequestsWearableUdp,
&sEnqueuedAssetRequestsSoundUdp,
&sEnqueuedAssetRequestsGestureUdp,
&sEnqueuedAssetRequestsOther
};
static LLTrace::CountStatHandle<> sDequeueAssetRequestsTempTextureHTTP ("dequeuedassetrequeststemptexturehttp",
"Number of temporary texture asset http requests dequeued"),
sDequeueAssetRequestsTempTextureUDP ("dequeuedassetrequeststemptextureudp",
"Number of temporary texture asset udp requests dequeued"),
sDequeueAssetRequestsNonTempTextureHTTP("dequeuedassetrequestsnontemptexturehttp",
"Number of texture asset http requests dequeued"),
sDequeueAssetRequestsNonTempTextureUDP ("dequeuedassetrequestsnontemptextureudp",
"Number of texture asset udp requests dequeued"),
sDequeuedAssetRequestsWearableUdp ("dequeuedassetrequestswearableudp",
"Number of wearable asset requests dequeued"),
sDequeuedAssetRequestsSoundUdp ("dequeuedassetrequestssoundudp",
"Number of sound asset requests dequeued"),
sDequeuedAssetRequestsGestureUdp ("dequeuedassetrequestsgestureudp",
"Number of gesture asset requests dequeued"),
sDequeuedAssetRequestsOther ("dequeuedassetrequestsother",
"Number of other asset requests dequeued");
static LLTrace::CountStatHandle<>* sDequeued[EVACCount] = {
&sDequeueAssetRequestsTempTextureHTTP,
&sDequeueAssetRequestsTempTextureUDP,
&sDequeueAssetRequestsNonTempTextureHTTP,
&sDequeueAssetRequestsNonTempTextureUDP,
&sDequeuedAssetRequestsWearableUdp,
&sDequeuedAssetRequestsSoundUdp,
&sDequeuedAssetRequestsGestureUdp,
&sDequeuedAssetRequestsOther
};
static LLTrace::EventStatHandle<F64Seconds > sResponseAssetRequestsTempTextureHTTP ("assetresponsetimestemptexturehttp",
"Time spent responding to temporary texture asset http requests"),
sResponseAssetRequestsTempTextureUDP ("assetresponsetimestemptextureudp",
"Time spent responding to temporary texture asset udp requests"),
sResponseAssetRequestsNonTempTextureHTTP("assetresponsetimesnontemptexturehttp",
"Time spent responding to texture asset http requests"),
sResponseAssetRequestsNonTempTextureUDP ("assetresponsetimesnontemptextureudp",
"Time spent responding to texture asset udp requests"),
sResponsedAssetRequestsWearableUdp ("assetresponsetimeswearableudp",
"Time spent responding to wearable asset requests"),
sResponsedAssetRequestsSoundUdp ("assetresponsetimessoundudp",
"Time spent responding to sound asset requests"),
sResponsedAssetRequestsGestureUdp ("assetresponsetimesgestureudp",
"Time spent responding to gesture asset requests"),
sResponsedAssetRequestsOther ("assetresponsetimesother",
"Time spent responding to other asset requests");
static LLTrace::EventStatHandle<F64Seconds >* sResponse[EVACCount] = {
&sResponseAssetRequestsTempTextureHTTP,
&sResponseAssetRequestsTempTextureUDP,
&sResponseAssetRequestsNonTempTextureHTTP,
&sResponseAssetRequestsNonTempTextureUDP,
&sResponsedAssetRequestsWearableUdp,
&sResponsedAssetRequestsSoundUdp,
&sResponsedAssetRequestsGestureUdp,
&sResponsedAssetRequestsOther
};
static LLTrace::DCCountStatHandle<> sEnqueued[EVACCount];
static LLTrace::DCCountStatHandle<> sDequeued[EVACCount];
static LLTrace::DCEventStatHandle<> sBytesFetched[EVACCount];
static LLTrace::DCEventStatHandle<F64Seconds > sResponse[EVACCount];
}
// ------------------------------------------------------
@ -353,6 +263,26 @@ void LLViewerAssetStats::setRegion(region_handle_t region_handle)
mRegionHandle = region_handle;
}
template <typename T>
void LLViewerAssetStats::getStat(LLTrace::Recording& rec, T& req, LLViewerAssetStatsFF::EViewerAssetCategories cat, bool compact_output)
{
using namespace LLViewerAssetStatsFF;
if (!compact_output
|| rec.getSampleCount(sEnqueued[cat])
|| rec.getSampleCount(sDequeued[cat])
|| rec.getSampleCount(sResponse[cat]))
{
req .enqueued(rec.getSampleCount(sEnqueued[cat]))
.dequeued(rec.getSampleCount(sDequeued[cat]))
.resp_count(rec.getSampleCount(sResponse[cat]))
.resp_min(rec.getMin(sResponse[cat]).value())
.resp_max(rec.getMax(sResponse[cat]).value())
.resp_mean(rec.getMean(sResponse[cat]).value())
.resp_mean_bytes(rec.getMean(sBytesFetched[cat]));
}
}
void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output)
{
using namespace LLViewerAssetStatsFF;
@ -365,108 +295,22 @@ void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output)
{
RegionStats& r = stats.regions.add();
LLTrace::Recording& rec = it->second;
if (!compact_output
|| rec.getSum(*sEnqueued[EVACTextureTempHTTPGet])
|| rec.getSum(*sDequeued[EVACTextureTempHTTPGet])
|| rec.getSum(*sResponse[EVACTextureTempHTTPGet]).value())
{
r.get_texture_temp_http .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureTempHTTPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACTextureTempHTTPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACTextureTempHTTPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACTextureTempHTTPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACTextureTempHTTPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACTextureTempHTTPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACTextureTempUDPGet])
|| rec.getSum(*sDequeued[EVACTextureTempUDPGet])
|| rec.getSum(*sResponse[EVACTextureTempUDPGet]).value())
{
r.get_texture_temp_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureTempUDPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACTextureTempUDPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACTextureTempUDPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACTextureTempUDPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACTextureTempUDPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACTextureTempUDPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACTextureNonTempHTTPGet])
|| rec.getSum(*sDequeued[EVACTextureNonTempHTTPGet])
|| rec.getSum(*sResponse[EVACTextureNonTempHTTPGet]).value())
{
r.get_texture_non_temp_http .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureNonTempHTTPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACTextureNonTempHTTPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACTextureNonTempHTTPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACTextureNonTempHTTPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACTextureNonTempHTTPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACTextureNonTempHTTPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACTextureNonTempUDPGet])
|| rec.getSum(*sDequeued[EVACTextureNonTempUDPGet])
|| rec.getSum(*sResponse[EVACTextureNonTempUDPGet]).value())
{
r.get_texture_non_temp_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACTextureNonTempUDPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACTextureNonTempUDPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACTextureNonTempUDPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACTextureNonTempUDPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACTextureNonTempUDPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACTextureNonTempUDPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACWearableUDPGet])
|| rec.getSum(*sDequeued[EVACWearableUDPGet])
|| rec.getSum(*sResponse[EVACWearableUDPGet]).value())
{
r.get_wearable_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACWearableUDPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACWearableUDPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACWearableUDPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACWearableUDPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACWearableUDPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACWearableUDPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACSoundUDPGet])
|| rec.getSum(*sDequeued[EVACSoundUDPGet])
|| rec.getSum(*sResponse[EVACSoundUDPGet]).value())
{
r.get_sound_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACSoundUDPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACSoundUDPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACSoundUDPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACSoundUDPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACSoundUDPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACSoundUDPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACGestureUDPGet])
|| rec.getSum(*sDequeued[EVACGestureUDPGet])
|| rec.getSum(*sResponse[EVACGestureUDPGet]).value())
{
r.get_gesture_udp .enqueued((S32)rec.getSum(*sEnqueued[EVACGestureUDPGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACGestureUDPGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACGestureUDPGet]).value())
.resp_min(rec.getMin(*sResponse[EVACGestureUDPGet]).value())
.resp_max(rec.getMax(*sResponse[EVACGestureUDPGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACGestureUDPGet]).value());
}
if (!compact_output
|| rec.getSum(*sEnqueued[EVACOtherGet])
|| rec.getSum(*sDequeued[EVACOtherGet])
|| rec.getSum(*sResponse[EVACOtherGet]).value())
{
r.get_other .enqueued((S32)rec.getSum(*sEnqueued[EVACOtherGet]))
.dequeued((S32)rec.getSum(*sDequeued[EVACOtherGet]))
.resp_count((S32)rec.getSum(*sResponse[EVACOtherGet]).value())
.resp_min(rec.getMin(*sResponse[EVACOtherGet]).value())
.resp_max(rec.getMax(*sResponse[EVACOtherGet]).value())
.resp_mean(rec.getMean(*sResponse[EVACOtherGet]).value());
}
getStat(rec, r.get_texture_temp_http, EVACTextureTempHTTPGet, compact_output);
getStat(rec, r.get_texture_temp_udp, EVACTextureTempUDPGet, compact_output);
getStat(rec, r.get_texture_non_temp_http, EVACTextureNonTempHTTPGet, compact_output);
getStat(rec, r.get_texture_non_temp_udp, EVACTextureNonTempUDPGet, compact_output);
getStat(rec, r.get_wearable_http, EVACWearableHTTPGet, compact_output);
getStat(rec, r.get_wearable_udp, EVACWearableUDPGet, compact_output);
getStat(rec, r.get_sound_http, EVACSoundHTTPGet, compact_output);
getStat(rec, r.get_sound_udp, EVACSoundUDPGet, compact_output);
getStat(rec, r.get_gesture_http, EVACGestureHTTPGet, compact_output);
getStat(rec, r.get_gesture_udp, EVACGestureUDPGet, compact_output);
getStat(rec, r.get_landmark_http, EVACLandmarkHTTPGet, compact_output);
getStat(rec, r.get_landmark_udp, EVACLandmarkUDPGet, compact_output);
getStat(rec, r.get_other_http, EVACOtherHTTPGet, compact_output);
getStat(rec, r.get_other_udp, EVACOtherUDPGet, compact_output);
S32 fps = (S32)rec.getLastValue(LLStatViewer::FPS_SAMPLE);
if (!compact_output || fps != 0)
{
@ -479,10 +323,10 @@ void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output)
grid_from_region_handle(it->first, &grid_x, &grid_y);
r .grid_x(grid_x)
.grid_y(grid_y)
.duration(F64Microseconds(rec.getDuration()).value());
.duration(F64Seconds(rec.getDuration()).value());
}
stats.duration(mCurRecording ? F64Microseconds(mCurRecording->getDuration()).value() : 0.0);
stats.duration(mCurRecording ? F64Seconds(mCurRecording->getDuration()).value() : 0.0);
}
LLSD LLViewerAssetStats::asLLSD(bool compact_output)
@ -518,21 +362,22 @@ void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp)
{
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
add(*sEnqueued[int(eac)], 1);
add(sEnqueued[int(eac)], 1);
}
void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp)
{
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
add(*sDequeued[int(eac)], 1);
add(sDequeued[int(eac)], 1);
}
void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration, F64 bytes)
{
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
record(*sResponse[int(eac)], F64Microseconds(duration));
record(sResponse[int(eac)], F64Seconds(duration));
record(sBytesFetched[int(eac)], bytes);
}
void init()
@ -561,7 +406,8 @@ LLViewerAssetStats::AssetRequestType::AssetRequestType()
resp_count("resp_count"),
resp_min("resp_min"),
resp_max("resp_max"),
resp_mean("resp_mean")
resp_mean("resp_mean"),
resp_mean_bytes("resp_mean_bytes")
{}
LLViewerAssetStats::FPSStats::FPSStats()
@ -576,10 +422,16 @@ LLViewerAssetStats::RegionStats::RegionStats()
get_texture_temp_udp("get_texture_temp_udp"),
get_texture_non_temp_http("get_texture_non_temp_http"),
get_texture_non_temp_udp("get_texture_non_temp_udp"),
get_wearable_http("get_wearable_http"),
get_wearable_udp("get_wearable_udp"),
get_sound_http("get_sound_http"),
get_sound_udp("get_sound_udp"),
get_gesture_http("get_gesture_http"),
get_gesture_udp("get_gesture_udp"),
get_other("get_other"),
get_landmark_http("get_landmark_http"),
get_landmark_udp("get_landmark_udp"),
get_other_http("get_other_http"),
get_other_udp("get_other_udp"),
fps("fps"),
grid_x("grid_x"),
grid_y("grid_y"),

View File

@ -39,6 +39,29 @@
#include "lltrace.h"
#include "llinitparam.h"
namespace LLViewerAssetStatsFF
{
enum EViewerAssetCategories
{
EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP
EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP
EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP
EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP
EVACWearableHTTPGet, //< Wearable GETs HTTP
EVACWearableUDPGet, //< Wearable GETs UDP
EVACSoundHTTPGet, //< Sound GETs HTTP
EVACSoundUDPGet, //< Sound GETs UDP
EVACGestureHTTPGet, //< Gesture GETs HTTP
EVACGestureUDPGet, //< Gesture GETs UDP
EVACLandmarkHTTPGet, //< Landmark GETs HTTP
EVACLandmarkUDPGet, //< Landmark GETs UDP
EVACOtherHTTPGet, //< Other GETs HTTP
EVACOtherUDPGet, //< Other GETs UDP
EVACCount // Must be last
};
}
/**
* @class LLViewerAssetStats
* @brief Records performance aspects of asset access operations.
@ -74,6 +97,7 @@
* LLViewerAssetStatsFF is provided for conditional test-and-call
* operations.
*/
class LLViewerAssetStats : public LLStopWatchControlsMixin<LLViewerAssetStats>
{
public:
@ -98,13 +122,14 @@ public:
resp_count;
Mandatory<F64> resp_min,
resp_max,
resp_mean;
resp_mean,
resp_mean_bytes;
AssetRequestType();
};
struct FPSStats : public LLInitParam::Block<FPSStats>
{
{
Mandatory<S32> count;
Mandatory<F64> min,
max,
@ -113,15 +138,21 @@ public:
};
struct RegionStats : public LLInitParam::Block<RegionStats>
{
{
Optional<AssetRequestType> get_texture_temp_http,
get_texture_temp_udp,
get_texture_non_temp_http,
get_texture_non_temp_udp,
get_wearable_http,
get_wearable_udp,
get_sound_http,
get_sound_udp,
get_gesture_http,
get_gesture_udp,
get_other;
get_landmark_http,
get_landmark_udp,
get_other_http,
get_other_udp;
Optional<FPSStats> fps;
Optional<S32> grid_x,
grid_y;
@ -165,6 +196,11 @@ public:
// Retrieve current metrics for all visited regions (NULL region UUID/handle excluded)
// Uses AssetStats structure seen above
void getStats(AssetStats& stats, bool compact_output);
// Retrieve a single asset request type (taken from a single region)
template <typename T>
void getStat(LLTrace::Recording& rec, T& req, LLViewerAssetStatsFF::EViewerAssetCategories cat, bool compact_output);
LLSD asLLSD(bool compact_output);
protected:
@ -205,19 +241,6 @@ extern LLViewerAssetStats * gViewerAssetStats;
namespace LLViewerAssetStatsFF
{
enum EViewerAssetCategories
{
EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP
EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP
EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP
EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP
EVACWearableUDPGet, //< Wearable GETs
EVACSoundUDPGet, //< Sound GETs
EVACGestureUDPGet, //< Gesture GETs
EVACOtherGet, //< Other GETs
EVACCount // Must be last
};
/**
* @brief Allocation and deallocation of globals.
@ -250,7 +273,7 @@ void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp);
void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp);
void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp,
LLViewerAssetStats::duration_t duration);
LLViewerAssetStats::duration_t duration, F64 bytes=0);
void record_avatar_stats();

View File

@ -33,9 +33,17 @@
#include "message.h"
#include "llagent.h"
#include "llappcorehttp.h"
#include "llviewerregion.h"
#include "lltransfersourceasset.h"
#include "lltransfertargetvfile.h"
#include "llviewerassetstats.h"
#include "llcoros.h"
#include "llcoproceduremanager.h"
#include "lleventcoro.h"
#include "llsdutil.h"
#include "llworld.h"
///----------------------------------------------------------------------------
/// LLViewerAssetRequest
@ -51,267 +59,283 @@
class LLViewerAssetRequest : public LLAssetRequest
{
public:
LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
: LLAssetRequest(uuid, type),
mMetricsStartTime(0)
{
}
LLViewerAssetRequest & operator=(const LLViewerAssetRequest &); // Not defined
// Default assignment operator valid
// virtual
~LLViewerAssetRequest()
{
recordMetrics();
}
LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type, bool with_http)
: LLAssetRequest(uuid, type),
mMetricsStartTime(0),
mWithHTTP(with_http)
{
}
LLViewerAssetRequest & operator=(const LLViewerAssetRequest &); // Not defined
// Default assignment operator valid
// virtual
~LLViewerAssetRequest()
{
recordMetrics();
}
protected:
void recordMetrics()
{
if (mMetricsStartTime.value())
{
// Okay, it appears this request was used for useful things. Record
// the expected dequeue and duration of request processing.
LLViewerAssetStatsFF::record_dequeue(mType, false, false);
LLViewerAssetStatsFF::record_response(mType, false, false,
(LLViewerAssetStatsFF::get_timestamp()
- mMetricsStartTime));
mMetricsStartTime = (U32Seconds)0;
}
}
void recordMetrics()
{
if (mMetricsStartTime.value())
{
// Okay, it appears this request was used for useful things. Record
// the expected dequeue and duration of request processing.
LLViewerAssetStatsFF::record_dequeue(mType, mWithHTTP, false);
LLViewerAssetStatsFF::record_response(mType, mWithHTTP, false,
(LLViewerAssetStatsFF::get_timestamp()
- mMetricsStartTime),
mBytesFetched);
mMetricsStartTime = (U32Seconds)0;
}
}
public:
LLViewerAssetStats::duration_t mMetricsStartTime;
LLViewerAssetStats::duration_t mMetricsStartTime;
bool mWithHTTP;
};
///----------------------------------------------------------------------------
/// LLViewerAssetStorage
///----------------------------------------------------------------------------
// Unused?
LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs,
const LLHost &upstream_host)
: LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host)
LLVFS *vfs, LLVFS *static_vfs,
const LLHost &upstream_host)
: LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host),
mAssetCoroCount(0),
mCountRequests(0),
mCountStarted(0),
mCountCompleted(0),
mCountSucceeded(0),
mTotalBytesFetched(0)
{
}
LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs)
: LLAssetStorage(msg, xfer, vfs, static_vfs)
LLVFS *vfs, LLVFS *static_vfs)
: LLAssetStorage(msg, xfer, vfs, static_vfs),
mAssetCoroCount(0),
mCountRequests(0),
mCountStarted(0),
mCountCompleted(0),
mCountSucceeded(0),
mTotalBytesFetched(0)
{
}
// virtual
void LLViewerAssetStorage::storeAssetData(
const LLTransactionID& tid,
LLAssetType::EType asset_type,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file,
bool is_priority,
bool store_local,
bool user_waiting,
F64Seconds timeout)
const LLTransactionID& tid,
LLAssetType::EType asset_type,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file,
bool is_priority,
bool store_local,
bool user_waiting,
F64Seconds timeout)
{
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type)
<< " ASSET_ID: " << asset_id << LL_ENDL;
if (mUpstreamHost.isOk())
{
if (mVFS->getExists(asset_id, asset_type))
{
// Pack data into this packet if we can fit it.
U8 buffer[MTUBYTES];
buffer[0] = 0;
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type)
<< " ASSET_ID: " << asset_id << LL_ENDL;
if (mUpstreamHost.isOk())
{
if (mVFS->getExists(asset_id, asset_type))
{
// Pack data into this packet if we can fit it.
U8 buffer[MTUBYTES];
buffer[0] = 0;
LLVFile vfile(mVFS, asset_id, asset_type, LLVFile::READ);
S32 asset_size = vfile.getSize();
LLVFile vfile(mVFS, asset_id, asset_type, LLVFile::READ);
S32 asset_size = vfile.getSize();
LLAssetRequest *req = new LLAssetRequest(asset_id, asset_type);
req->mUpCallback = callback;
req->mUserData = user_data;
LLAssetRequest *req = new LLAssetRequest(asset_id, asset_type);
req->mUpCallback = callback;
req->mUserData = user_data;
if (asset_size < 1)
{
// This can happen if there's a bug in our code or if the VFS has been corrupted.
LL_WARNS() << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << LL_ENDL;
// LLAssetStorage metric: Zero size VFS
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
if (asset_size < 1)
{
// This can happen if there's a bug in our code or if the VFS has been corrupted.
LL_WARNS("AssetStorage") << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << LL_ENDL;
// LLAssetStorage metric: Zero size VFS
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
delete req;
if (callback)
{
callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_VFS_CORRUPT);
}
return;
}
else
{
// LLAssetStorage metric: Successful Request
S32 size = mVFS->getSize(asset_id, asset_type);
const char *message = "Added to upload queue";
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message );
delete req;
if (callback)
{
callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_VFS_CORRUPT);
}
return;
}
else
{
// LLAssetStorage metric: Successful Request
S32 size = mVFS->getSize(asset_id, asset_type);
const char *message = "Added to upload queue";
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message );
if(is_priority)
{
mPendingUploads.push_front(req);
}
else
{
mPendingUploads.push_back(req);
}
}
if(is_priority)
{
mPendingUploads.push_front(req);
}
else
{
mPendingUploads.push_back(req);
}
}
// Read the data from the VFS if it'll fit in this packet.
if (asset_size + 100 < MTUBYTES)
{
BOOL res = vfile.read(buffer, asset_size); /* Flawfinder: ignore */
S32 bytes_read = res ? vfile.getLastBytesRead() : 0;
if( bytes_read == asset_size )
{
req->mDataSentInFirstPacket = TRUE;
//LL_INFOS() << "LLViewerAssetStorage::createAsset sending data in first packet" << LL_ENDL;
}
else
{
LL_WARNS() << "Probable corruption in VFS file, aborting store asset data" << LL_ENDL;
// Read the data from the VFS if it'll fit in this packet.
if (asset_size + 100 < MTUBYTES)
{
BOOL res = vfile.read(buffer, asset_size); /* Flawfinder: ignore */
S32 bytes_read = res ? vfile.getLastBytesRead() : 0;
if( bytes_read == asset_size )
{
req->mDataSentInFirstPacket = TRUE;
//LL_INFOS() << "LLViewerAssetStorage::createAsset sending data in first packet" << LL_ENDL;
}
else
{
LL_WARNS("AssetStorage") << "Probable corruption in VFS file, aborting store asset data" << LL_ENDL;
// LLAssetStorage metric: VFS corrupt - bogus size
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" );
// LLAssetStorage metric: VFS corrupt - bogus size
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" );
if (callback)
{
callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT);
}
return;
}
}
else
{
// Too big, do an xfer
buffer[0] = 0;
asset_size = 0;
}
mMessageSys->newMessageFast(_PREHASH_AssetUploadRequest);
mMessageSys->nextBlockFast(_PREHASH_AssetBlock);
mMessageSys->addUUIDFast(_PREHASH_TransactionID, tid);
mMessageSys->addS8Fast(_PREHASH_Type, (S8)asset_type);
mMessageSys->addBOOLFast(_PREHASH_Tempfile, temp_file);
mMessageSys->addBOOLFast(_PREHASH_StoreLocal, store_local);
mMessageSys->addBinaryDataFast( _PREHASH_AssetData, buffer, asset_size );
mMessageSys->sendReliable(mUpstreamHost);
}
else
{
LL_WARNS() << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL;
// LLAssetStorage metric: Zero size VFS
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
if (callback)
{
callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE);
}
}
}
else
{
LL_WARNS() << "Attempt to move asset store request upstream w/o valid upstream provider" << LL_ENDL;
// LLAssetStorage metric: Upstream provider dead
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" );
if (callback)
{
callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
}
}
if (callback)
{
callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT);
}
return;
}
}
else
{
// Too big, do an xfer
buffer[0] = 0;
asset_size = 0;
}
mMessageSys->newMessageFast(_PREHASH_AssetUploadRequest);
mMessageSys->nextBlockFast(_PREHASH_AssetBlock);
mMessageSys->addUUIDFast(_PREHASH_TransactionID, tid);
mMessageSys->addS8Fast(_PREHASH_Type, (S8)asset_type);
mMessageSys->addBOOLFast(_PREHASH_Tempfile, temp_file);
mMessageSys->addBOOLFast(_PREHASH_StoreLocal, store_local);
mMessageSys->addBinaryDataFast( _PREHASH_AssetData, buffer, asset_size );
mMessageSys->sendReliable(mUpstreamHost);
}
else
{
LL_WARNS("AssetStorage") << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL;
// LLAssetStorage metric: Zero size VFS
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
if (callback)
{
callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE);
}
}
}
else
{
LL_WARNS("AssetStorage") << "Attempt to move asset store request upstream w/o valid upstream provider" << LL_ENDL;
// LLAssetStorage metric: Upstream provider dead
reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" );
if (callback)
{
callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
}
}
}
void LLViewerAssetStorage::storeAssetData(
const std::string& filename,
const LLTransactionID& tid,
LLAssetType::EType asset_type,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file,
bool is_priority,
bool user_waiting,
F64Seconds timeout)
const std::string& filename,
const LLTransactionID& tid,
LLAssetType::EType asset_type,
LLStoreAssetCallback callback,
void* user_data,
bool temp_file,
bool is_priority,
bool user_waiting,
F64Seconds timeout)
{
if(filename.empty())
{
// LLAssetStorage metric: no filename
reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" );
LL_ERRS() << "No filename specified" << LL_ENDL;
return;
}
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL;
if(filename.empty())
{
// LLAssetStorage metric: no filename
reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" );
LL_ERRS() << "No filename specified" << LL_ENDL;
return;
}
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL;
LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL;
LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL;
S32 size = 0;
LLFILE* fp = LLFile::fopen(filename, "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
}
if( size )
{
LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
legacy->mUpCallback = callback;
legacy->mUserData = user_data;
S32 size = 0;
LLFILE* fp = LLFile::fopen(filename, "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
}
if( size )
{
LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
legacy->mUpCallback = callback;
legacy->mUserData = user_data;
LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE);
LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE);
file.setMaxSize(size);
file.setMaxSize(size);
const S32 buf_size = 65536;
U8 copy_buf[buf_size];
while ((size = (S32)fread(copy_buf, 1, buf_size, fp)))
{
file.write(copy_buf, size);
}
fclose(fp);
const S32 buf_size = 65536;
U8 copy_buf[buf_size];
while ((size = (S32)fread(copy_buf, 1, buf_size, fp)))
{
file.write(copy_buf, size);
}
fclose(fp);
// if this upload fails, the caller needs to setup a new tempfile for us
if (temp_file)
{
LLFile::remove(filename);
}
// if this upload fails, the caller needs to setup a new tempfile for us
if (temp_file)
{
LLFile::remove(filename);
}
// LLAssetStorage metric: Success not needed; handled in the overloaded method here:
// LLAssetStorage metric: Success not needed; handled in the overloaded method here:
LLViewerAssetStorage::storeAssetData(
tid,
asset_type,
legacyStoreDataCallback,
(void**)legacy,
temp_file,
is_priority);
}
else // size == 0 (but previous block changes size)
{
if( fp )
{
// LLAssetStorage metric: Zero size
reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" );
}
else
{
// LLAssetStorage metric: Missing File
reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" );
}
if (callback)
{
callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE);
}
}
LLViewerAssetStorage::storeAssetData(
tid,
asset_type,
legacyStoreDataCallback,
(void**)legacy,
temp_file,
is_priority);
}
else // size == 0 (but previous block changes size)
{
if( fp )
{
// LLAssetStorage metric: Zero size
reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" );
}
else
{
// LLAssetStorage metric: Missing File
reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" );
}
if (callback)
{
callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE);
}
}
}
@ -334,56 +358,218 @@ void LLViewerAssetStorage::storeAssetData(
// virtual
void LLViewerAssetStorage::_queueDataRequest(
const LLUUID& uuid,
LLAssetType::EType atype,
LLGetAssetCallback callback,
void *user_data,
BOOL duplicate,
BOOL is_priority)
const LLUUID& uuid,
LLAssetType::EType atype,
LLGetAssetCallback callback,
void *user_data,
BOOL duplicate,
BOOL is_priority)
{
if (mUpstreamHost.isOk())
{
// stash the callback info so we can find it after we get the response message
LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype);
req->mDownCallback = callback;
req->mUserData = user_data;
req->mIsPriority = is_priority;
if (!duplicate)
{
// Only collect metrics for non-duplicate requests. Others
// are piggy-backing and will artificially lower averages.
req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
}
mPendingDownloads.push_back(req);
if (!duplicate)
{
// send request message to our upstream data provider
// Create a new asset transfer.
LLTransferSourceParamsAsset spa;
spa.setAsset(uuid, atype);
// Set our destination file, and the completion callback.
LLTransferTargetParamsVFile tpvf;
tpvf.setAsset(uuid, atype);
tpvf.setCallback(downloadCompleteCallback, *req);
LL_DEBUGS("AssetStorage") << "Starting transfer for " << uuid << LL_ENDL;
LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
LLViewerAssetStatsFF::record_enqueue(atype, false, false);
}
}
else
{
// uh-oh, we shouldn't have gotten here
LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL;
if (callback)
{
callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
}
}
mCountRequests++;
queueRequestHttp(uuid, atype, callback, user_data, duplicate, is_priority);
}
void LLViewerAssetStorage::queueRequestHttp(
const LLUUID& uuid,
LLAssetType::EType atype,
LLGetAssetCallback callback,
void *user_data,
BOOL duplicate,
BOOL is_priority)
{
LL_DEBUGS("ViewerAsset") << "Request asset via HTTP " << uuid << " type " << LLAssetType::lookup(atype) << LL_ENDL;
bool with_http = true;
LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype, with_http);
req->mDownCallback = callback;
req->mUserData = user_data;
req->mIsPriority = is_priority;
if (!duplicate)
{
// Only collect metrics for non-duplicate requests. Others
// are piggy-backing and will artificially lower averages.
req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
}
mPendingDownloads.push_back(req);
// This is the same as the current UDP logic - don't re-request a duplicate.
if (!duplicate)
{
bool with_http = true;
bool is_temp = false;
LLViewerAssetStatsFF::record_enqueue(atype, with_http, is_temp);
LLCoprocedureManager::instance().enqueueCoprocedure("AssetStorage","LLViewerAssetStorage::assetRequestCoro",
boost::bind(&LLViewerAssetStorage::assetRequestCoro, this, req, uuid, atype, callback, user_data));
}
}
void LLViewerAssetStorage::capsRecvForRegion(const LLUUID& region_id, std::string pumpname)
{
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(region_id);
if (!regionp)
{
LL_WARNS("ViewerAsset") << "region not found for region_id " << region_id << LL_ENDL;
}
else
{
mViewerAssetUrl = regionp->getViewerAssetUrl();
}
LLEventPumps::instance().obtain(pumpname).post(LLSD());
}
struct LLScopedIncrement
{
LLScopedIncrement(S32& counter):
mCounter(counter)
{
++mCounter;
}
~LLScopedIncrement()
{
--mCounter;
}
S32& mCounter;
};
void LLViewerAssetStorage::assetRequestCoro(
LLViewerAssetRequest *req,
const LLUUID uuid,
LLAssetType::EType atype,
LLGetAssetCallback callback,
void *user_data)
{
LLScopedIncrement coro_count_boost(mAssetCoroCount);
mCountStarted++;
S32 result_code = LL_ERR_NOERR;
LLExtStat ext_status = LL_EXSTAT_NONE;
if (!gAgent.getRegion())
{
LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LL_EXSTAT_NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
return;
}
else if (!gAgent.getRegion()->capabilitiesReceived())
{
LL_WARNS_ONCE("ViewerAsset") << "Waiting for capabilities" << LL_ENDL;
LLEventStream capsRecv("waitForCaps", true);
gAgent.getRegion()->setCapabilitiesReceivedCallback(
boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName()));
llcoro::suspendUntilEventOn(capsRecv);
LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL;
LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL;
}
if (mViewerAssetUrl.empty() && gAgent.getRegion())
{
mViewerAssetUrl = gAgent.getRegion()->getViewerAssetUrl();
}
if (mViewerAssetUrl.empty())
{
LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LL_EXSTAT_NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
return;
}
std::string url = getAssetURL(mViewerAssetUrl, uuid,atype);
LL_DEBUGS("ViewerAsset") << "request url: " << url << LL_ENDL;
LLCore::HttpRequest::policy_t httpPolicy(LLAppCoreHttp::AP_TEXTURE);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("assetRequestCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts);
if (LLApp::isQuitting())
{
// Bail out if result arrives after shutdown has been started.
return;
}
mCountCompleted++;
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
{
LL_DEBUGS("ViewerAsset") << "request failed, status " << status.toTerseString() << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LL_EXSTAT_NONE;
}
else
{
LL_DEBUGS("ViewerAsset") << "request succeeded, url " << url << LL_ENDL;
const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
S32 size = raw.size();
if (size > 0)
{
mTotalBytesFetched += size;
// This create-then-rename flow is modeled on
// LLTransferTargetVFile, which is what was used in the UDP
// case.
LLUUID temp_id;
temp_id.generate();
LLVFile vf(gAssetStorage->mVFS, temp_id, atype, LLVFile::WRITE);
vf.setMaxSize(size);
req->mBytesFetched = size;
if (!vf.write(raw.data(),size))
{
// TODO asset-http: handle error
LL_WARNS("ViewerAsset") << "Failure in vf.write()" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LL_EXSTAT_VFS_CORRUPT;
}
else if (!vf.rename(uuid, atype))
{
LL_WARNS("ViewerAsset") << "rename failed" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LL_EXSTAT_VFS_CORRUPT;
}
else
{
mCountSucceeded++;
}
}
else
{
// TODO asset-http: handle invalid size case
LL_WARNS("ViewerAsset") << "bad size" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LL_EXSTAT_NONE;
}
}
// Clean up pending downloads and trigger callbacks
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
}
std::string LLViewerAssetStorage::getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype)
{
std::string type_name = LLAssetType::lookup(atype);
std::string url = cap_url + "/?" + type_name + "_id=" + uuid.asString();
return url;
}
void LLViewerAssetStorage::logAssetStorageInfo()
{
LLMemory::logMemoryInfo(true);
LL_INFOS("AssetStorage") << "Active coros " << mAssetCoroCount << LL_ENDL;
LL_INFOS("AssetStorage") << "mPendingDownloads size " << mPendingDownloads.size() << LL_ENDL;
LL_INFOS("AssetStorage") << "mCountStarted " << mCountStarted << LL_ENDL;
LL_INFOS("AssetStorage") << "mCountCompleted " << mCountCompleted << LL_ENDL;
LL_INFOS("AssetStorage") << "mCountSucceeded " << mCountSucceeded << LL_ENDL;
LL_INFOS("AssetStorage") << "mTotalBytesFetched " << mTotalBytesFetched << LL_ENDL;
}

View File

@ -28,10 +28,12 @@
#define LLVIEWERASSETSTORAGE_H
#include "llassetstorage.h"
//#include "curl/curl.h"
#include "llcorehttputil.h"
class LLVFile;
class LLViewerAssetRequest;
class LLViewerAssetStorage : public LLAssetStorage
{
public:
@ -41,7 +43,6 @@ public:
LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs);
using LLAssetStorage::storeAssetData;
virtual void storeAssetData(
const LLTransactionID& tid,
LLAssetType::EType atype,
@ -65,8 +66,6 @@ public:
F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
protected:
using LLAssetStorage::_queueDataRequest;
// virtual
void _queueDataRequest(const LLUUID& uuid,
LLAssetType::EType type,
@ -74,6 +73,33 @@ protected:
void *user_data,
BOOL duplicate,
BOOL is_priority);
void queueRequestHttp(const LLUUID& uuid,
LLAssetType::EType type,
void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
void *user_data,
BOOL duplicate,
BOOL is_priority);
void capsRecvForRegion(const LLUUID& region_id, std::string pumpname);
void assetRequestCoro(LLViewerAssetRequest *req,
const LLUUID uuid,
LLAssetType::EType atype,
void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
void *user_data);
std::string getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype);
void logAssetStorageInfo();
std::string mViewerAssetUrl;
S32 mAssetCoroCount;
S32 mCountRequests;
S32 mCountStarted;
S32 mCountCompleted;
S32 mCountSucceeded;
S64 mTotalBytesFetched;
};
#endif

View File

@ -106,6 +106,7 @@ const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f;
U32 gRecentFrameCount = 0; // number of 'recent' frames
LLFrameTimer gRecentFPSTime;
LLFrameTimer gRecentMemoryTime;
LLFrameTimer gAssetStorageLogTime;
// Rendering stuff
void pre_show_depth_buffer();
@ -226,6 +227,12 @@ void display_stats()
LLMemory::logMemoryInfo(TRUE) ;
gRecentMemoryTime.reset();
}
F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency");
if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq)
{
gAssetStorageLogTime.reset();
gAssetStorage->logAssetStorageInfo();
}
}
static LLTrace::BlockTimerStatHandle FTM_PICK("Picking");

View File

@ -521,7 +521,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
mColoName("unknown"),
mProductSKU("unknown"),
mProductName("unknown"),
mHttpUrl(""),
mViewerAssetUrl(""),
mCacheLoaded(FALSE),
mCacheDirty(FALSE),
mReleaseNotesRequested(FALSE),
@ -2843,12 +2843,9 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("IsExperienceAdmin");
capabilityNames.append("IsExperienceContributor");
capabilityNames.append("RegionExperiences");
capabilityNames.append("GetMesh");
capabilityNames.append("GetMesh2");
capabilityNames.append("GetMetadata");
capabilityNames.append("GetObjectCost");
capabilityNames.append("GetObjectPhysicsData");
capabilityNames.append("GetTexture");
capabilityNames.append("GroupAPIv1");
capabilityNames.append("GroupMemberData");
capabilityNames.append("GroupProposalBallot");
@ -2895,6 +2892,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("UpdateScriptAgent");
capabilityNames.append("UpdateScriptTask");
capabilityNames.append("UploadBakedTexture");
capabilityNames.append("ViewerAsset");
capabilityNames.append("ViewerMetrics");
capabilityNames.append("ViewerStartAuction");
capabilityNames.append("ViewerStats");
@ -2961,9 +2959,9 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
else
{
mImpl->mCapabilities[name] = url;
if(name == "GetTexture")
if(name == "ViewerAsset")
{
mHttpUrl = url ;
mViewerAssetUrl = url;
}
}
}
@ -2974,9 +2972,9 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri
if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) )
{
mImpl->mSecondCapabilitiesTracker[name] = url;
if(name == "GetTexture")
if(name == "ViewerAsset")
{
mHttpUrl = url ;
mViewerAssetUrl = url;
}
}
}

View File

@ -354,7 +354,7 @@ public:
friend std::ostream& operator<<(std::ostream &s, const LLViewerRegion &region);
/// implements LLCapabilityProvider
virtual std::string getDescription() const;
std::string getHttpUrl() const { return mHttpUrl ;}
std::string getViewerAssetUrl() const { return mViewerAssetUrl; }
U32 getNumOfVisibleGroups() const;
U32 getNumOfActiveCachedObjects() const;
@ -506,7 +506,7 @@ private:
std::string mColoName;
std::string mProductSKU;
std::string mProductName;
std::string mHttpUrl ;
std::string mViewerAssetUrl ;
// Maps local ids to cache entries.
// Regions can have order 10,000 objects, so assume

View File

@ -9387,6 +9387,3 @@ BOOL LLVOAvatar::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type,
// non-self avatars don't have wearables
return FALSE;
}

View File

@ -71,25 +71,33 @@ static const char * all_keys[] =
{
"duration",
"fps",
"get_other",
"get_other_http",
"get_other_udp",
"get_texture_temp_http",
"get_texture_temp_udp",
"get_texture_non_temp_http",
"get_texture_non_temp_udp",
"get_wearable_http",
"get_wearable_udp",
"get_sound_http",
"get_sound_udp",
"get_gesture_http",
"get_gesture_udp"
};
static const char * resp_keys[] =
{
"get_other",
"get_other_http",
"get_other_udp",
"get_texture_temp_http",
"get_texture_temp_udp",
"get_texture_non_temp_http",
"get_texture_non_temp_udp",
"get_wearable_http",
"get_wearable_udp",
"get_sound_http",
"get_sound_udp",
"get_gesture_http",
"get_gesture_udp"
};
@ -540,11 +548,17 @@ namespace tut
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_wearable_http][enqueued] is 2", (2 == sd["get_wearable_http"]["enqueued"].asInteger()));
ensure("sd[get_wearable_http][dequeued] is 2", (2 == sd["get_wearable_http"]["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()));
ensure("sd[get_wearable_udp][enqueued] is 2", (2 == sd["get_wearable_udp"]["enqueued"].asInteger()));
ensure("sd[get_wearable_udp][dequeued] is 2", (2 == sd["get_wearable_udp"]["dequeued"].asInteger()));
ensure("sd[get_other_http][enqueued] is 2", (2 == sd["get_other_http"]["enqueued"].asInteger()));
ensure("sd[get_other_http][dequeued] is 0", (0 == sd["get_other_http"]["dequeued"].asInteger()));
ensure("sd[get_other_udp][enqueued] is 2", (2 == sd["get_other_udp"]["enqueued"].asInteger()));
ensure("sd[get_other_udp][dequeued] is 0", (0 == sd["get_other_udp"]["dequeued"].asInteger()));
// Reset and check zeros...
// Reset leaves current region in place

View File

@ -34,6 +34,7 @@
*
*/
#include "linden_common.h"
#include "llerrorcontrol.h"
#include "lltut.h"
@ -684,4 +685,5 @@ int main(int argc, char **argv)
return retval;
//delete mycallback;
}

View File

@ -0,0 +1,102 @@
#!runpy.sh
"""\
This module contains tools for analyzing viewer asset metrics logs produced by the viewer.
$LicenseInfo:firstyear=2016&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2016, 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$
"""
import argparse
from lxml import etree
from llbase import llsd
def get_metrics_record(infiles):
for filename in args.infiles:
f = open(filename)
# get an iterable
context = etree.iterparse(f, events=("start", "end"))
# turn it into an iterator
context = iter(context)
# get the root element
event, root = context.next()
try:
for event, elem in context:
if event == "end" and elem.tag == "llsd":
xmlstr = etree.tostring(elem, encoding="utf8", method="xml")
sd = llsd.parse_xml(xmlstr)
yield sd
except etree.XMLSyntaxError:
print "Fell off end of document"
f.close()
def update_stats(stats,rec):
for region in rec["regions"]:
region_key = (region["grid_x"],region["grid_y"])
#print "region",region_key
for field, val in region.iteritems():
if field in ["duration","grid_x","grid_y"]:
continue
if field == "fps":
# handle fps record as special case
pass
else:
#print "field",field
stats.setdefault(field,{})
type_stats = stats.get(field)
newcount = val["resp_count"]
#print "field",field,"add count",newcount
type_stats["count"] = type_stats.get("count",0) + val["resp_count"]
#print "field",field,"count",type_stats["count"]
if (newcount>0):
type_stats["sum"] = type_stats.get("sum",0) + val["resp_count"] * val["resp_mean"]
type_stats["sum_bytes"] = type_stats.get("sum_bytes",0) + val["resp_count"] * val.get("resp_mean_bytes",0)
type_stats["enqueued"] = type_stats.get("enqueued",0) + val["enqueued"]
type_stats["dequeued"] = type_stats.get("dequeued",0) + val["dequeued"]
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="process metric xml files for viewer asset fetching")
parser.add_argument("--verbose", action="store_true",help="verbose flag")
parser.add_argument("infiles", nargs="+", help="name of .xml files to process")
args = parser.parse_args()
#print "process files:",args.infiles
stats = {}
for rec in get_metrics_record(args.infiles):
#print "record",rec
update_stats(stats,rec)
for key in sorted(stats.keys()):
val = stats[key]
if val["count"] > 0:
print key,"count",val["count"],"mean_time",val["sum"]/val["count"],"mean_bytes",val["sum_bytes"]/val["count"],"net bytes/sec",val["sum_bytes"]/val["sum"],"enqueued",val["enqueued"],"dequeued",val["dequeued"]
else:
print key,"count",val["count"],"enqueued",val["enqueued"],"dequeued",val["dequeued"]