Catch up with LL regarding viewer stat recording.
This commit is contained in:
@@ -53,6 +53,7 @@
|
||||
#include "llviewertexture.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewerstats.h"
|
||||
#include "llviewerstatsrecorder.h"
|
||||
#include "llworld.h"
|
||||
#include "llstartup.h"
|
||||
#include "llbuffer.h"
|
||||
@@ -61,6 +62,9 @@ class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout;
|
||||
extern AIHTTPTimeoutPolicy lcl_responder_timeout;
|
||||
|
||||
LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128);
|
||||
LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
class LLTextureFetchWorker : public LLWorkerClass
|
||||
{
|
||||
@@ -250,6 +254,8 @@ private:
|
||||
S32 mDecodedDiscard;
|
||||
LLFrameTimer mRequestedTimer;
|
||||
LLFrameTimer mFetchTimer;
|
||||
LLTimer mCacheReadTimer;
|
||||
F32 mCacheReadTime;
|
||||
LLTextureCache::handle_t mCacheReadHandle;
|
||||
LLTextureCache::handle_t mCacheWriteHandle;
|
||||
std::vector<U8> mHttpBuffer;
|
||||
@@ -289,9 +295,6 @@ private:
|
||||
S32 mLastPacket;
|
||||
U16 mTotalPackets;
|
||||
U8 mImageCodec;
|
||||
#if HTTP_METRICS
|
||||
LLViewerAssetStats::duration_t mMetricsStartTime;
|
||||
#endif
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -384,20 +387,6 @@ public:
|
||||
}
|
||||
|
||||
mFetcher->removeFromHTTPQueue(mID, data_size);
|
||||
|
||||
#if HTTP_METRICS
|
||||
if (worker->mMetricsStartTime)
|
||||
{
|
||||
LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
true,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
|
||||
LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
|
||||
worker->mMetricsStartTime = 0;
|
||||
}
|
||||
LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
true,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -514,230 +503,6 @@ static bool sgConnectionThrottle() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HTTP_METRICS
|
||||
// Cross-thread messaging for asset metrics.
|
||||
|
||||
/**
|
||||
* @brief Base class for cross-thread requests made of the fetcher
|
||||
*
|
||||
* I believe the intent of the LLQueuedThread class was to
|
||||
* have these operations derived from LLQueuedThread::QueuedRequest
|
||||
* but the texture fetcher has elected to manage the queue
|
||||
* in its own manner. So these are free-standing objects which are
|
||||
* managed in simple FIFO order on the mCommands queue of the
|
||||
* LLTextureFetch object.
|
||||
*
|
||||
* What each represents is a simple command sent from an
|
||||
* outside thread into the TextureFetch thread to be processed
|
||||
* in order and in a timely fashion (though not an absolute
|
||||
* higher priority than other operations of the thread).
|
||||
* Each operation derives a new class from the base customizing
|
||||
* members, constructors and the doWork() method to effect
|
||||
* the command.
|
||||
*
|
||||
* The flow is one-directional. There are two global instances
|
||||
* of the LLViewerAssetStats collector, one for the main program's
|
||||
* thread pointed to by gViewerAssetStatsMain and one for the
|
||||
* TextureFetch thread pointed to by gViewerAssetStatsThread1.
|
||||
* Common operations has each thread recording metrics events
|
||||
* into the respective collector unconcerned with locking and
|
||||
* the state of any other thread. But when the agent moves into
|
||||
* a different region or the metrics timer expires and a report
|
||||
* needs to be sent back to the grid, messaging across threads
|
||||
* is required to distribute data and perform global actions.
|
||||
* In pseudo-UML, it looks like:
|
||||
*
|
||||
* Main Thread1
|
||||
* . .
|
||||
* . .
|
||||
* +-----+ .
|
||||
* | AM | .
|
||||
* +--+--+ .
|
||||
* +-------+ | .
|
||||
* | Main | +--+--+ .
|
||||
* | | | SRE |---. .
|
||||
* | Stats | +-----+ \ .
|
||||
* | | | \ (uuid) +-----+
|
||||
* | Coll. | +--+--+ `-------->| SR |
|
||||
* +-------+ | MSC | +--+--+
|
||||
* | ^ +-----+ |
|
||||
* | | (uuid) / . +-----+ (uuid)
|
||||
* | `--------' . | MSC |---------.
|
||||
* | . +-----+ |
|
||||
* | +-----+ . v
|
||||
* | | TE | . +-------+
|
||||
* | +--+--+ . | Thd1 |
|
||||
* | | . | |
|
||||
* | +-----+ . | Stats |
|
||||
* `--------->| RSC | . | |
|
||||
* +--+--+ . | Coll. |
|
||||
* | . +-------+
|
||||
* +--+--+ . |
|
||||
* | SME |---. . |
|
||||
* +-----+ \ . |
|
||||
* . \ (clone) +-----+ |
|
||||
* . `-------->| SM | |
|
||||
* . +--+--+ |
|
||||
* . | |
|
||||
* . +-----+ |
|
||||
* . | RSC |<--------'
|
||||
* . +-----+
|
||||
* . |
|
||||
* . +-----+
|
||||
* . | CP |--> HTTP POST
|
||||
* . +-----+
|
||||
* . .
|
||||
* . .
|
||||
*
|
||||
*
|
||||
* Key:
|
||||
*
|
||||
* SRE - Set Region Enqueued. Enqueue a 'Set Region' command in
|
||||
* the other thread providing the new UUID of the region.
|
||||
* TFReqSetRegion carries the data.
|
||||
* SR - Set Region. New region UUID is sent to the thread-local
|
||||
* collector.
|
||||
* SME - Send Metrics Enqueued. Enqueue a 'Send Metrics' command
|
||||
* including an ownership transfer of a cloned LLViewerAssetStats.
|
||||
* TFReqSendMetrics carries the data.
|
||||
* SM - Send Metrics. Global metrics reporting operation. Takes
|
||||
* the cloned stats from the command, merges it with the
|
||||
* thread's local stats, converts to LLSD and sends it on
|
||||
* to the grid.
|
||||
* AM - Agent Moved. Agent has completed some sort of move to a
|
||||
* new region.
|
||||
* TE - Timer Expired. Metrics timer has expired (on the order
|
||||
* of 10 minutes).
|
||||
* CP - CURL Post
|
||||
* MSC - Modify Stats Collector. State change in the thread-local
|
||||
* collector. Typically a region change which affects the
|
||||
* global pointers used to find the 'current stats'.
|
||||
* RSC - Read Stats Collector. Extract collector data cloning it
|
||||
* (i.e. deep copy) when necessary.
|
||||
*
|
||||
*/
|
||||
class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
|
||||
{
|
||||
public:
|
||||
// Default ctors and assignment operator are correct.
|
||||
|
||||
virtual ~TFRequest()
|
||||
{}
|
||||
|
||||
// Patterned after QueuedRequest's method but expected behavior
|
||||
// is different. Always expected to complete on the first call
|
||||
// and work dispatcher will assume the same and delete the
|
||||
// request after invocation.
|
||||
virtual bool doWork(LLTextureFetch * fetcher) = 0;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Implements a 'Set Region' cross-thread command.
|
||||
*
|
||||
* When an agent moves to a new region, subsequent metrics need
|
||||
* to be binned into a new or existing stats collection in 1:1
|
||||
* relationship with the region. We communicate this region
|
||||
* change across the threads involved in the communication with
|
||||
* this message.
|
||||
*
|
||||
* Corresponds to LLTextureFetch::commandSetRegion()
|
||||
*/
|
||||
class TFReqSetRegion : public LLTextureFetch::TFRequest
|
||||
{
|
||||
public:
|
||||
TFReqSetRegion(U64 region_handle)
|
||||
: LLTextureFetch::TFRequest(),
|
||||
mRegionHandle(region_handle)
|
||||
{}
|
||||
TFReqSetRegion & operator=(const TFReqSetRegion &); // Not defined
|
||||
|
||||
virtual ~TFReqSetRegion()
|
||||
{}
|
||||
|
||||
virtual bool doWork(LLTextureFetch * fetcher);
|
||||
|
||||
public:
|
||||
const U64 mRegionHandle;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Implements a 'Send Metrics' cross-thread command.
|
||||
*
|
||||
* This is the big operation. The main thread gathers metrics
|
||||
* for a period of minutes into LLViewerAssetStats and other
|
||||
* objects then makes a snapshot of the data by cloning the
|
||||
* collector. This command transfers the clone, along with a few
|
||||
* additional arguments (UUIDs), handing ownership to the
|
||||
* TextureFetch thread. It then merges its own data into the
|
||||
* cloned copy, converts to LLSD and kicks off an HTTP POST of
|
||||
* the resulting data to the currently active metrics collector.
|
||||
*
|
||||
* Corresponds to LLTextureFetch::commandSendMetrics()
|
||||
*/
|
||||
|
||||
class TFReqSendMetrics : public LLTextureFetch::TFRequest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct the 'Send Metrics' command to have the TextureFetch
|
||||
* thread add and log metrics data.
|
||||
*
|
||||
* @param caps_url URL of a "ViewerMetrics" Caps target
|
||||
* to receive the data. Does not have to
|
||||
* be associated with a particular region.
|
||||
*
|
||||
* @param session_id UUID of the agent's session.
|
||||
*
|
||||
* @param agent_id UUID of the agent. (Being pure here...)
|
||||
*
|
||||
* @param main_stats Pointer to a clone of the main thread's
|
||||
* LLViewerAssetStats data. Thread1 takes
|
||||
* ownership of the copy and disposes of it
|
||||
* when done.
|
||||
*/
|
||||
|
||||
TFReqSendMetrics(const std::string & caps_url,
|
||||
const LLUUID & session_id,
|
||||
const LLUUID & agent_id,
|
||||
LLViewerAssetStats * main_stats)
|
||||
: LLTextureFetch::TFRequest(),
|
||||
mCapsURL(caps_url),
|
||||
mSessionID(session_id),
|
||||
mAgentID(agent_id),
|
||||
mMainStats(main_stats)
|
||||
{}
|
||||
TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined
|
||||
|
||||
virtual ~TFReqSendMetrics();
|
||||
|
||||
virtual bool doWork(LLTextureFetch * fetcher);
|
||||
|
||||
public:
|
||||
const std::string mCapsURL;
|
||||
const LLUUID mSessionID;
|
||||
const LLUUID mAgentID;
|
||||
LLViewerAssetStats * mMainStats;
|
||||
};
|
||||
|
||||
/*
|
||||
* Examines the merged viewer metrics report and if found to be too long,
|
||||
* will attempt to truncate it in some reasonable fashion.
|
||||
*
|
||||
* @param max_regions Limit of regions allowed in report.
|
||||
*
|
||||
* @param metrics Full, merged viewer metrics report.
|
||||
*
|
||||
* @returns If data was truncated, returns true.
|
||||
*/
|
||||
bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
|
||||
|
||||
} // end of anonymous namespace
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//static
|
||||
@@ -757,11 +522,6 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
|
||||
"DONE",
|
||||
};
|
||||
|
||||
#if HTTP_METRICS
|
||||
// static
|
||||
volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break
|
||||
#endif
|
||||
|
||||
// called from MAIN THREAD
|
||||
|
||||
LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
@@ -786,6 +546,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
mRequestedDiscard(-1),
|
||||
mLoadedDiscard(-1),
|
||||
mDecodedDiscard(-1),
|
||||
mCacheReadTime(0.f),
|
||||
mCacheReadHandle(LLTextureCache::nullHandle()),
|
||||
mCacheWriteHandle(LLTextureCache::nullHandle()),
|
||||
mRequestedSize(0),
|
||||
@@ -810,9 +571,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
|
||||
mLastPacket(-1),
|
||||
mTotalPackets(0),
|
||||
mImageCodec(IMG_CODEC_INVALID)
|
||||
#if HTTP_METRICS
|
||||
,mMetricsStartTime(0)
|
||||
#endif
|
||||
{
|
||||
mCanUseNET = mUrl.empty() ;
|
||||
|
||||
@@ -1064,6 +822,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
|
||||
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
|
||||
offset, size, responder);
|
||||
mCacheReadTimer.reset();
|
||||
}
|
||||
else if (mUrl.empty())
|
||||
{
|
||||
@@ -1072,8 +831,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
|
||||
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
|
||||
offset, size, responder);
|
||||
mCacheReadTimer.reset();
|
||||
}
|
||||
else if(mCanUseHTTP)
|
||||
else if(!mUrl.empty() && mCanUseHTTP)
|
||||
{
|
||||
if (!(mUrl.compare(0, 7, "http://") == 0))
|
||||
{
|
||||
@@ -1101,6 +861,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
//This should never happen
|
||||
//
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1124,7 +887,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize()
|
||||
<< " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight())
|
||||
<< " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
|
||||
// fall through
|
||||
LLTextureFetch::sCacheHitRate.addValue(100.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1139,7 +902,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
|
||||
mState = LOAD_FROM_NETWORK;
|
||||
}
|
||||
|
||||
// fall through
|
||||
LLTextureFetch::sCacheHitRate.addValue(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1198,15 +963,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
mRequestedDiscard = mDesiredDiscard;
|
||||
mSentRequest = QUEUED;
|
||||
mFetcher->addToNetworkQueue(this);
|
||||
#if HTTP_METRICS
|
||||
if (! mMetricsStartTime)
|
||||
{
|
||||
mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
|
||||
}
|
||||
LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
false,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
#endif
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
|
||||
return false;
|
||||
@@ -1217,12 +973,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
//llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
|
||||
// Make certain this is in the network queue
|
||||
//mFetcher->addToNetworkQueue(this);
|
||||
//if (! mMetricsStartTime)
|
||||
//{
|
||||
// mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
|
||||
//}
|
||||
//LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
|
||||
// LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
return false;
|
||||
}
|
||||
@@ -1247,33 +997,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
|
||||
mState = DECODE_IMAGE;
|
||||
mWriteToCacheState = SHOULD_WRITE;
|
||||
|
||||
#if HTTP_METRICS
|
||||
if (mMetricsStartTime)
|
||||
{
|
||||
LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
false,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType,
|
||||
LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
|
||||
mMetricsStartTime = 0;
|
||||
}
|
||||
LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
false,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
mFetcher->addToNetworkQueue(this); // failsafe
|
||||
#if HTTP_METRICS
|
||||
if (! mMetricsStartTime)
|
||||
{
|
||||
mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
|
||||
}
|
||||
LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
false,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
#endif
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
}
|
||||
return false;
|
||||
@@ -1340,15 +1067,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
mState = WAIT_HTTP_REQ;
|
||||
|
||||
mFetcher->addToHTTPQueue(mID);
|
||||
#if HTTP_METRICS
|
||||
if (! mMetricsStartTime)
|
||||
{
|
||||
mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
|
||||
}
|
||||
LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
|
||||
true,
|
||||
LLImageBase::TYPE_AVATAR_BAKE == mType);
|
||||
#endif
|
||||
|
||||
if(mRequestedOffset>0)
|
||||
{
|
||||
@@ -1573,11 +1291,12 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
if (mState == DECODE_IMAGE)
|
||||
{
|
||||
static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled");
|
||||
if(textures_decode_disabled)
|
||||
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
|
||||
if (textures_decode_disabled)
|
||||
{
|
||||
// for debug use, don't decode
|
||||
mState = DONE;
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1585,7 +1304,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
{
|
||||
// We aborted, don't decode
|
||||
mState = DONE;
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1595,7 +1313,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
|
||||
//abort, don't decode
|
||||
mState = DONE;
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
return true;
|
||||
}
|
||||
if (mLoadedDiscard < 0)
|
||||
@@ -1604,10 +1321,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
|
||||
//abort, don't decode
|
||||
mState = DONE;
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
|
||||
return true;
|
||||
}
|
||||
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
|
||||
|
||||
mRawImage = NULL;
|
||||
mAuxImage = NULL;
|
||||
llassert_always(mFormattedImage.notNull());
|
||||
@@ -1899,6 +1615,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
|
||||
LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL;
|
||||
if (data_size > 0)
|
||||
{
|
||||
LLViewerStatsRecorder::instance().textureFetch(data_size);
|
||||
// *TODO: set the formatted image data here directly to avoid the copy
|
||||
llassert(mHttpBuffer.empty());
|
||||
mHttpBuffer.resize(data_size);
|
||||
@@ -1932,6 +1649,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
|
||||
mLoaded = TRUE;
|
||||
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
|
||||
|
||||
LLViewerStatsRecorder::instance().log(0.2f);
|
||||
return data_size ;
|
||||
}
|
||||
|
||||
@@ -2017,6 +1735,7 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag
|
||||
mDecoded = TRUE;
|
||||
// llinfos << mID << " : DECODE COMPLETE " << llendl;
|
||||
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
|
||||
mCacheReadTime = mCacheReadTimer.getElapsedTimeF32();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2058,13 +1777,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
|
||||
mTextureBandwidth(0),
|
||||
mHTTPTextureBits(0),
|
||||
mTotalHTTPRequests(0)
|
||||
#if HTTP_METRICS
|
||||
,mQAMode(qa_mode)
|
||||
#endif
|
||||
{
|
||||
#if HTTP_METRICS
|
||||
mCurlPOSTRequestCount = 0;
|
||||
#endif
|
||||
mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
|
||||
}
|
||||
|
||||
@@ -2072,14 +1785,6 @@ LLTextureFetch::~LLTextureFetch()
|
||||
{
|
||||
clearDeleteList() ;
|
||||
|
||||
#if HTTP_METRICS
|
||||
while (! mCommands.empty())
|
||||
{
|
||||
TFRequest * req(mCommands.front());
|
||||
mCommands.erase(mCommands.begin());
|
||||
delete req;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ~LLQueuedThread() called here
|
||||
}
|
||||
@@ -2341,6 +2046,11 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
|
||||
discard_level = worker->mDecodedDiscard;
|
||||
raw = worker->mRawImage;
|
||||
aux = worker->mAuxImage;
|
||||
F32 cache_read_time = worker->mCacheReadTime;
|
||||
if (cache_read_time != 0.f)
|
||||
{
|
||||
sCacheReadLatency.addValue(cache_read_time * 1000.f);
|
||||
}
|
||||
res = true;
|
||||
LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL;
|
||||
worker->unlockWorkMutex();
|
||||
@@ -2393,10 +2103,6 @@ S32 LLTextureFetch::getPending()
|
||||
LLMutexLock lock(&mQueueMutex);
|
||||
|
||||
res = mRequestQueue.size();
|
||||
#if HTTP_METRICS
|
||||
res += mCurlPOSTRequestCount;
|
||||
res += mCommands.size();
|
||||
#endif
|
||||
}
|
||||
unlockData();
|
||||
return res;
|
||||
@@ -2414,22 +2120,7 @@ bool LLTextureFetch::runCondition()
|
||||
//
|
||||
// Changes here may need to be reflected in getPending().
|
||||
|
||||
#if HTTP_METRICS
|
||||
bool have_no_commands(false);
|
||||
{
|
||||
LLMutexLock lock(&mQueueMutex);
|
||||
|
||||
have_no_commands = mCommands.empty();
|
||||
}
|
||||
|
||||
bool have_no_curl_requests(0 == mCurlPOSTRequestCount);
|
||||
|
||||
return ! (have_no_commands
|
||||
&& have_no_curl_requests
|
||||
&& (mRequestQueue.empty() && mIdleThread)); // From base class
|
||||
#else
|
||||
return !(mRequestQueue.empty() && mIdleThread);
|
||||
#endif
|
||||
return ! (mRequestQueue.empty() && mIdleThread); // From base class
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2437,10 +2128,6 @@ bool LLTextureFetch::runCondition()
|
||||
// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
|
||||
void LLTextureFetch::commonUpdate()
|
||||
{
|
||||
#if HTTP_METRICS
|
||||
// Run a cross-thread command, if any.
|
||||
cmdDoWork();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -2799,11 +2486,16 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
|
||||
mNetworkQueueMutex.unlock() ;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLViewerStatsRecorder::instance().textureFetch(data_size);
|
||||
LLViewerStatsRecorder::instance().log(0.1f);
|
||||
|
||||
worker->lockWorkMutex();
|
||||
|
||||
// Copy header data into image object
|
||||
worker->mImageCodec = codec;
|
||||
worker->mTotalPackets = packets;
|
||||
|
||||
// Copy header data into image object
|
||||
worker->mImageCodec = codec;
|
||||
worker->mTotalPackets = packets;
|
||||
worker->mFileSize = (S32)totalbytes;
|
||||
llassert_always(totalbytes > 0);
|
||||
llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
|
||||
@@ -2844,8 +2536,12 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
|
||||
mNetworkQueueMutex.unlock() ;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLViewerStatsRecorder::instance().textureFetch(data_size);
|
||||
LLViewerStatsRecorder::instance().log(0.1f);
|
||||
|
||||
worker->lockWorkMutex();
|
||||
|
||||
|
||||
res = worker->insertPacket(packet_num, data, data_size);
|
||||
|
||||
@@ -2959,277 +2655,12 @@ void LLTextureFetch::dump()
|
||||
<< " STATE: " << worker->sStateDescs[worker->mState]
|
||||
<< llendl;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// cross-thread command methods
|
||||
|
||||
#if HTTP_METRICS
|
||||
void LLTextureFetch::commandSetRegion(U64 region_handle)
|
||||
{
|
||||
TFReqSetRegion * req = new TFReqSetRegion(region_handle);
|
||||
|
||||
cmdEnqueue(req);
|
||||
}
|
||||
|
||||
void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
|
||||
const LLUUID & session_id,
|
||||
const LLUUID & agent_id,
|
||||
LLViewerAssetStats * main_stats)
|
||||
{
|
||||
TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
|
||||
|
||||
cmdEnqueue(req);
|
||||
}
|
||||
|
||||
void LLTextureFetch::commandDataBreak()
|
||||
{
|
||||
// The pedantically correct way to implement this is to create a command
|
||||
// request object in the above fashion and enqueue it. However, this is
|
||||
// simple data of an advisorial not operational nature and this case
|
||||
// of shared-write access is tolerable.
|
||||
|
||||
LLTextureFetch::svMetricsDataBreak = true;
|
||||
}
|
||||
|
||||
void LLTextureFetch::cmdEnqueue(TFRequest * req)
|
||||
{
|
||||
lockQueue();
|
||||
mCommands.push_back(req);
|
||||
unlockQueue();
|
||||
|
||||
unpause();
|
||||
}
|
||||
|
||||
LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue()
|
||||
{
|
||||
TFRequest * ret = 0;
|
||||
|
||||
lockQueue();
|
||||
if (! mCommands.empty())
|
||||
llinfos << "LLTextureFetch ACTIVE_HTTP:" << llendl;
|
||||
for (queue_t::const_iterator iter(mHTTPTextureQueue.begin());
|
||||
mHTTPTextureQueue.end() != iter;
|
||||
++iter)
|
||||
{
|
||||
ret = mCommands.front();
|
||||
mCommands.erase(mCommands.begin());
|
||||
}
|
||||
unlockQueue();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLTextureFetch::cmdDoWork()
|
||||
{
|
||||
if (mDebugPause)
|
||||
{
|
||||
return; // debug: don't do any work
|
||||
}
|
||||
|
||||
TFRequest * req = cmdDequeue();
|
||||
if (req)
|
||||
{
|
||||
// One request per pass should really be enough for this.
|
||||
req->doWork(this);
|
||||
delete req;
|
||||
llinfos << " ID: " << (*iter) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Private (anonymous) class methods implementing the command scheme.
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* Implements the 'Set Region' command.
|
||||
*
|
||||
* Thread: Thread1 (TextureFetch)
|
||||
*/
|
||||
bool
|
||||
TFReqSetRegion::doWork(LLTextureFetch *)
|
||||
{
|
||||
LLViewerAssetStatsFF::set_region_thread1(mRegionHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TFReqSendMetrics::~TFReqSendMetrics()
|
||||
{
|
||||
delete mMainStats;
|
||||
mMainStats = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements the 'Send Metrics' command. Takes over
|
||||
* ownership of the passed LLViewerAssetStats pointer.
|
||||
*
|
||||
* Thread: Thread1 (TextureFetch)
|
||||
*/
|
||||
bool
|
||||
TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
|
||||
{
|
||||
/*
|
||||
* HTTP POST responder. Doesn't do much but tries to
|
||||
* detect simple breaks in recording the metrics stream.
|
||||
*
|
||||
* The 'volatile' modifiers don't indicate signals,
|
||||
* mmap'd memory or threads, really. They indicate that
|
||||
* the referenced data is part of a pseudo-closure for
|
||||
* this responder rather than being required for correct
|
||||
* operation.
|
||||
*
|
||||
* We don't try very hard with the POST request. We give
|
||||
* it one shot and that's more-or-less it. With a proper
|
||||
* refactoring of the LLQueuedThread usage, these POSTs
|
||||
* could be put in a request object and made more reliable.
|
||||
*/
|
||||
class lcl_responder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
lcl_responder(LLTextureFetch * fetcher,
|
||||
S32 expected_sequence,
|
||||
volatile const S32 & live_sequence,
|
||||
volatile bool & reporting_break,
|
||||
volatile bool & reporting_started)
|
||||
: mFetcher(fetcher),
|
||||
mExpectedSequence(expected_sequence),
|
||||
mLiveSequence(live_sequence),
|
||||
mReportingBreak(reporting_break),
|
||||
mReportingStarted(reporting_started)
|
||||
{
|
||||
mFetcher->incrCurlPOSTCount();
|
||||
}
|
||||
|
||||
~lcl_responder()
|
||||
{
|
||||
mFetcher->decrCurlPOSTCount();
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status_num, const std::string & reason)
|
||||
{
|
||||
if (mLiveSequence == mExpectedSequence)
|
||||
{
|
||||
mReportingBreak = true;
|
||||
}
|
||||
LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service. Reason: "
|
||||
<< reason << LL_ENDL;
|
||||
}
|
||||
|
||||
/*virtual*/ void result(const LLSD & content)
|
||||
{
|
||||
if (mLiveSequence == mExpectedSequence)
|
||||
{
|
||||
mReportingBreak = false;
|
||||
mReportingStarted = true;
|
||||
}
|
||||
}
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return lcl_responder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "lcl_responder"; }
|
||||
|
||||
private:
|
||||
LLTextureFetch * mFetcher;
|
||||
S32 mExpectedSequence;
|
||||
volatile const S32 & mLiveSequence;
|
||||
volatile bool & mReportingBreak;
|
||||
volatile bool & mReportingStarted;
|
||||
|
||||
}; // class lcl_responder
|
||||
|
||||
if (! gViewerAssetStatsThread1)
|
||||
return true;
|
||||
|
||||
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;
|
||||
|
||||
// Merge existing stats into those from main, convert to LLSD
|
||||
main_stats.merge(*gViewerAssetStatsThread1);
|
||||
LLSD merged_llsd = main_stats.asLLSD(true);
|
||||
|
||||
// Add some additional meta fields to the content
|
||||
merged_llsd["session_id"] = mSessionID;
|
||||
merged_llsd["agent_id"] = mAgentID;
|
||||
merged_llsd["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics
|
||||
merged_llsd["sequence"] = report_sequence; // Sequence number
|
||||
merged_llsd["initial"] = ! reporting_started; // Initial data from viewer
|
||||
merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report
|
||||
|
||||
// Update sequence number
|
||||
if (S32_MAX == ++report_sequence)
|
||||
report_sequence = 0;
|
||||
|
||||
// Limit the size of the stats report if necessary.
|
||||
merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd);
|
||||
|
||||
if (! mCapsURL.empty())
|
||||
{
|
||||
LLHTTPClient::post(mCapsURL,
|
||||
merged_llsd,
|
||||
new lcl_responder(fetcher,
|
||||
report_sequence,
|
||||
report_sequence,
|
||||
LLTextureFetch::svMetricsDataBreak,
|
||||
reporting_started));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLTextureFetch::svMetricsDataBreak = true;
|
||||
}
|
||||
|
||||
// In QA mode, Metrics submode, log the result for ease of testing
|
||||
if (fetcher->isQAMode())
|
||||
{
|
||||
LL_INFOS("Textures") << merged_llsd << LL_ENDL;
|
||||
}
|
||||
|
||||
gViewerAssetStatsThread1->reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
truncate_viewer_metrics(int max_regions, LLSD & metrics)
|
||||
{
|
||||
static const LLSD::String reg_tag("regions");
|
||||
static const LLSD::String duration_tag("duration");
|
||||
|
||||
LLSD & reg_map(metrics[reg_tag]);
|
||||
if (reg_map.size() <= max_regions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build map of region hashes ordered by duration
|
||||
typedef std::multimap<LLSD::Real, int> reg_ordered_list_t;
|
||||
reg_ordered_list_t regions_by_duration;
|
||||
|
||||
int ind(0);
|
||||
LLSD::array_const_iterator it_end(reg_map.endArray());
|
||||
for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind)
|
||||
{
|
||||
LLSD::Real duration = (*it)[duration_tag].asReal();
|
||||
regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind));
|
||||
}
|
||||
|
||||
// Build a replacement regions array with the longest-persistence regions
|
||||
LLSD new_region(LLSD::emptyArray());
|
||||
reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend());
|
||||
reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin());
|
||||
for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2)
|
||||
{
|
||||
new_region.append(reg_map[it2->second]);
|
||||
}
|
||||
reg_map = new_region;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user