Add AIHTTPView, a HTTP Debug Console - press Ctrl-Shift-7

This commit is contained in:
Aleric Inglewood
2013-06-01 16:14:32 +02:00
parent 5c05a04a2c
commit 98badb94da
12 changed files with 471 additions and 14 deletions

View File

@@ -197,6 +197,9 @@ U32 getNumHTTPQueued(void);
// Returns the number of curl requests currently added to the multi handle.
U32 getNumHTTPAdded(void);
// Return the maximum number of total allowed added curl requests.
U32 getMaxHTTPAdded(void);
// This used to be LLAppViewer::getTextureFetch()->getNumHTTPRequests().
// Returns the number of active curl easy handles (that are actually attempting to download something).
U32 getNumHTTPRunning(void);

View File

@@ -84,6 +84,7 @@ AIPerService::CapabilityType::CapabilityType(void) :
mQueuedCommands(0),
mAdded(0),
mFlags(0),
mDownloading(0),
mMaxPipelinedRequests(CurlConcurrentConnectionsPerService)
{
}
@@ -263,11 +264,16 @@ void AIPerService::added_to_multi_handle(AICapabilityType capability_type)
++mTotalAdded;
}
void AIPerService::removed_from_multi_handle(AICapabilityType capability_type)
void AIPerService::removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something)
{
llassert(mTotalAdded > 0 && mCapabilityType[capability_type].mAdded > 0);
--mCapabilityType[capability_type].mAdded;
if (downloaded_something)
{
llassert(mCapabilityType[capability_type].mDownloading > 0);
--mCapabilityType[capability_type].mDownloading;
}
--mTotalAdded;
llassert(mTotalAdded >= 0 && mCapabilityType[capability_type].mAdded >= 0);
}
void AIPerService::queue(AICurlEasyRequest const& easy_request, AICapabilityType capability_type)
@@ -450,7 +456,7 @@ void AIPerService::Approvement::honored(void)
if (!mHonored)
{
mHonored = true;
AICurlPrivate::PerService_wat per_service_w(*mPerServicePtr);
PerService_wat per_service_w(*mPerServicePtr);
llassert(per_service_w->mCapabilityType[mCapabilityType].mApprovedRequests > 0);
per_service_w->mCapabilityType[mCapabilityType].mApprovedRequests--;
}

View File

@@ -43,12 +43,15 @@
#include <string>
#include <deque>
#include <map>
#include <iterator>
#include <algorithm>
#include <boost/intrusive_ptr.hpp>
#include "aithreadsafe.h"
#include "aiaverage.h"
class AICurlEasyRequest;
class AIPerService;
class AIServiceBar;
namespace AICurlPrivate {
namespace curlthread { class MultiHandle; }
@@ -59,6 +62,8 @@ class ThreadSafeBufferedCurlEasyRequest;
// Forward declaration of BufferedCurlEasyRequestPtr (see aicurlprivate.h).
typedef boost::intrusive_ptr<ThreadSafeBufferedCurlEasyRequest> BufferedCurlEasyRequestPtr;
} // namespace AICurlPrivate
// AIPerService objects are created by the curl thread and destructed by the main thread.
// We need locking.
typedef AIThreadSafeSimpleDC<AIPerService> threadsafe_PerService;
@@ -66,8 +71,6 @@ typedef AIAccessConst<AIPerService> PerService_crat;
typedef AIAccess<AIPerService> PerService_rat;
typedef AIAccess<AIPerService> PerService_wat;
} // namespace AICurlPrivate
// We can't put threadsafe_PerService in a std::map because you can't copy a mutex.
// Therefore, use an intrusive pointer for the threadsafe type.
typedef boost::intrusive_ptr<AICurlPrivate::RefCountedThreadSafePerService> AIPerServicePtr;
@@ -93,12 +96,13 @@ enum AICapabilityType { // {Capabilities} [Responders]
// for that service already have been reached. And to keep track of the bandwidth usage, and the
// number of queued requests in the pipeline, for this service.
class AIPerService {
private:
public:
typedef std::map<std::string, AIPerServicePtr> instance_map_type;
typedef AIThreadSafeSimpleDC<instance_map_type> threadsafe_instance_map_type;
typedef AIAccess<instance_map_type> instance_map_rat;
typedef AIAccess<instance_map_type> instance_map_wat;
private:
static threadsafe_instance_map_type sInstanceMap; // Map of AIPerService instances with the hostname as key.
friend class AIThreadSafeSimpleDC<AIPerService>; // threadsafe_PerService
@@ -120,6 +124,10 @@ class AIPerService {
// Remove everything. Called upon viewer exit.
static void purge(void);
// Make a copy of the instanceMap and then run 'action(per_service)' on each AIPerService object.
template<class Action>
static void copy_forEach(Action const& action);
private:
static U16 const ctf_empty = 1;
static U16 const ctf_full = 2;
@@ -135,6 +143,7 @@ class AIPerService {
U16 mFlags; // ctf_empty: Set to true when the queue becomes precisely empty.
// ctf_full : Set to true when the queue is popped and then still isn't empty;
// ctf_starvation: Set to true when the queue was about to be popped but was already empty.
U32 mDownloading; // The number of active easy handles with this service for which data was received.
U32 mMaxPipelinedRequests; // The maximum number of accepted requests for this service and (approved) capability type, that didn't finish yet.
// Declare, not define, constructor and destructor - in order to avoid instantiation of queued_request_type from header.
@@ -144,6 +153,7 @@ class AIPerService {
S32 pipelined_requests(void) const { return mApprovedRequests + mQueuedCommands + mQueuedRequests.size() + mAdded; }
};
friend class AIServiceBar;
CapabilityType mCapabilityType[number_of_capability_types];
AIAverage mHTTPBandwidth; // Keeps track on number of bytes received for this service in the past second.
@@ -203,8 +213,9 @@ class AIPerService {
public:
void added_to_command_queue(AICapabilityType capability_type) { ++mCapabilityType[capability_type].mQueuedCommands; }
void removed_from_command_queue(AICapabilityType capability_type) { --mCapabilityType[capability_type].mQueuedCommands; llassert(mCapabilityType[capability_type].mQueuedCommands >= 0); }
void added_to_multi_handle(AICapabilityType capability_type); // Called when an easy handle for this host has been added to the multi handle.
void removed_from_multi_handle(AICapabilityType capability_type); // Called when an easy handle for this host is removed again from the multi handle.
void added_to_multi_handle(AICapabilityType capability_type); // Called when an easy handle for this host has been added to the multi handle.
void removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something); // Called when an easy handle for this host is removed again from the multi handle.
void download_started(AICapabilityType capability_type) { ++mCapabilityType[capability_type].mDownloading; }
bool throttled(void) const; // Returns true if the maximum number of allowed requests for this host have been added to the multi handle.
void queue(AICurlEasyRequest const& easy_request, AICapabilityType capability_type); // Add easy_request to the queue.
@@ -222,6 +233,7 @@ class AIPerService {
static void setNoHTTPBandwidthThrottling(bool nb) { sNoHTTPBandwidthThrottling = nb; }
static void setHTTPThrottleBandwidth(F32 max_kbps) { sHTTPThrottleBandwidth125 = 125.f * max_kbps; }
static size_t getHTTPThrottleBandwidth125(void) { return sHTTPThrottleBandwidth125; }
static F32 throttleFraction(void) { return ThrottleFraction_wat(sThrottleFraction)->fraction / 1024.f; }
// Called when CurlConcurrentConnectionsPerService changes.
static void adjust_concurrent_connections(int increment);
@@ -275,4 +287,17 @@ extern U32 CurlConcurrentConnectionsPerService;
} // namespace AICurlPrivate
template<class Action>
void AIPerService::copy_forEach(Action const& action)
{
// Make a copy so we don't need to keep the lock on sInstanceMap for too long.
std::vector<std::pair<instance_map_type::key_type, instance_map_type::mapped_type> > current_services;
{
instance_map_rat instance_map_r(sInstanceMap);
std::copy(instance_map_r->begin(), instance_map_r->end(), std::back_inserter(current_services));
}
// Apply the functor on each of the services.
std::for_each(current_services.begin(), current_services.end(), action);
}
#endif // AICURLPERSERVICE_H

View File

@@ -463,6 +463,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
// Return the capability type of this request.
AICapabilityType capability_type(void) const { llassert(mCapabilityType != number_of_capability_types); return mCapabilityType; }
// Return true if any data was received.
bool received_data(void) const { return mTotalRawBytes > 0; }
};
inline ThreadSafeBufferedCurlEasyRequest* CurlEasyRequest::get_lockobj(void)

View File

@@ -1721,8 +1721,7 @@ bool MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request, bool f
AICurlEasyRequest_wat curl_easy_request_w(*easy_request);
capability_type = curl_easy_request_w->capability_type();
per_service = curl_easy_request_w->getPerServicePtr();
// Never throttle on bandwidth if there are no handles running (sTotalAdded == 1, the long poll connection).
bool too_much_bandwidth = sTotalAdded > 1 && !curl_easy_request_w->approved() && AIPerService::checkBandwidthUsage(per_service, get_clock_count() * HTTPTimeout::sClockWidth_40ms);
bool too_much_bandwidth = !curl_easy_request_w->approved() && AIPerService::checkBandwidthUsage(per_service, get_clock_count() * HTTPTimeout::sClockWidth_40ms);
PerService_wat per_service_w(*per_service);
if (!too_much_bandwidth && sTotalAdded < curl_max_total_concurrent_connections && !per_service_w->throttled())
{
@@ -1791,10 +1790,11 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons
AIPerServicePtr per_service;
{
AICurlEasyRequest_wat curl_easy_request_w(**iter);
bool downloaded_something = curl_easy_request_w->received_data();
res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle);
capability_type = curl_easy_request_w->capability_type();
per_service = curl_easy_request_w->getPerServicePtr();
PerService_wat(*per_service)->removed_from_multi_handle(capability_type); // (About to be) removed from mAddedEasyRequests.
PerService_wat(*per_service)->removed_from_multi_handle(capability_type, downloaded_something); // (About to be) removed from mAddedEasyRequests.
#ifdef SHOW_ASSERT
curl_easy_request_w->mRemovedPerCommand = as_per_command;
#endif
@@ -2137,6 +2137,12 @@ void BufferedCurlEasyRequest::update_body_bandwidth(void)
getinfo(CURLINFO_SIZE_DOWNLOAD, &size_download);
size_t total_raw_bytes = size_download;
size_t raw_bytes = total_raw_bytes - mTotalRawBytes;
if (mTotalRawBytes == 0 && total_raw_bytes > 0)
{
// Update service/capability type administration for the HTTP Debug Console.
PerService_wat per_service_w(*mPerServicePtr);
per_service_w->download_started(mCapabilityType);
}
mTotalRawBytes = total_raw_bytes;
// Note that in some cases (like HTTP_PARTIAL_CONTENT), the output of CURLINFO_SIZE_DOWNLOAD lags
// behind and will return 0 the first time, and the value of the previous chunk the next time.
@@ -2589,6 +2595,11 @@ U32 getNumHTTPAdded(void)
return AICurlPrivate::curlthread::MultiHandle::total_added_size();
}
U32 getMaxHTTPAdded(void)
{
return AICurlPrivate::curlthread::curl_max_total_concurrent_connections;
}
size_t getHTTPBandwidth(void)
{
using namespace AICurlPrivate;