diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 00d9de67b..c42a6a4a1 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -289,6 +289,20 @@ static unsigned int encoded_version(int major, int minor, int patch) namespace AICurlInterface { +//static +LLAtomicU32 Stats::easy_calls; +LLAtomicU32 Stats::easy_errors; +LLAtomicU32 Stats::easy_init_calls; +LLAtomicU32 Stats::easy_init_errors; +LLAtomicU32 Stats::easy_cleanup_calls; +LLAtomicU32 Stats::multi_calls; +LLAtomicU32 Stats::multi_errors; +LLAtomicU32 Stats::AICurlEasyRequest_count; +LLAtomicU32 Stats::AICurlEasyRequestStateMachine_count; +LLAtomicU32 Stats::BufferedCurlEasyRequest_count; +LLAtomicU32 Stats::ResponderBase_count; +LLAtomicU32 Stats::ThreadSafeBufferedCurlEasyRequest_count; + // MAIN-THREAD void initCurl(void) { @@ -417,6 +431,39 @@ void setCAPath(std::string const& path) CertificateAuthority_w->path = path; } +//static +void Stats::print(void) +{ + int const easy_handles = easy_init_calls - easy_init_errors - easy_cleanup_calls; + llinfos_nf << "============ CURL STATS ============" << llendl; + llinfos_nf << " Curl multi errors/calls : " << std::dec << multi_errors << "/" << multi_calls << llendl; + llinfos_nf << " Curl easy errors/calls : " << std::dec << easy_errors << "/" << easy_calls << llendl; + llinfos_nf << " curl_easy_init() errors/calls : " << std::dec << easy_init_errors << "/" << easy_init_calls << llendl; + llinfos_nf << " Current number of curl easy handles: " << std::dec << easy_handles << llendl; +#ifdef DEBUG_CURLIO + llinfos_nf << " Current number of BufferedCurlEasyRequest objects: " << BufferedCurlEasyRequest_count << llendl; + llinfos_nf << " Current number of ThreadSafeBufferedCurlEasyRequest objects: " << ThreadSafeBufferedCurlEasyRequest_count << llendl; + llinfos_nf << " Current number of AICurlEasyRequest objects: " << AICurlEasyRequest_count << llendl; + llinfos_nf << " Current number of AICurlEasyRequestStateMachine objects: " << AICurlEasyRequestStateMachine_count << llendl; +#endif + llinfos_nf << " Current number of Responders: " << ResponderBase_count << llendl; + llinfos_nf << "========= END OF CURL STATS =========" << llendl; + // Leak tests. + // There is one easy handle per CurlEasyHandle, and BufferedCurlEasyRequest is derived from that. + // It is not allowed to create CurlEasyHandle (or CurlEasyRequest) directly, only by creating a BufferedCurlEasyRequest, + // therefore the number of existing easy handles must equal the number of BufferedCurlEasyRequest objects. + llassert(easy_handles == BufferedCurlEasyRequest_count); + // Even more strict, BufferedCurlEasyRequest may not be created directly either, only as + // base class of ThreadSafeBufferedCurlEasyRequest. + llassert(BufferedCurlEasyRequest_count == ThreadSafeBufferedCurlEasyRequest_count); + // Each AICurlEasyRequestStateMachine is responsible for exactly one easy handle. + llassert(easy_handles >= AICurlEasyRequest_count); + // Each AICurlEasyRequestStateMachine has one AICurlEasyRequest member. + llassert(AICurlEasyRequest_count >= AICurlEasyRequestStateMachine_count); + // AIFIXME: is this really always the case? And why? + llassert(easy_handles <= ResponderBase_count); +} + } // namespace AICurlInterface //================================================================================== @@ -426,31 +473,13 @@ void setCAPath(std::string const& path) namespace AICurlPrivate { +using AICurlInterface::Stats; + #if defined(CWDEBUG) || defined(DEBUG_CURLIO) // CURLOPT_DEBUGFUNCTION function. extern int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr); #endif -//static -LLAtomicU32 Stats::easy_calls; -LLAtomicU32 Stats::easy_errors; -LLAtomicU32 Stats::easy_init_calls; -LLAtomicU32 Stats::easy_init_errors; -LLAtomicU32 Stats::easy_cleanup_calls; -LLAtomicU32 Stats::multi_calls; -LLAtomicU32 Stats::multi_errors; - -//static -void Stats::print(void) -{ - llinfos_nf << "============ CURL STATS ============" << llendl; - llinfos_nf << " Curl multi errors/calls : " << std::dec << multi_errors << "/" << multi_calls << llendl; - llinfos_nf << " Curl easy errors/calls : " << std::dec << easy_errors << "/" << easy_calls << llendl; - llinfos_nf << " curl_easy_init() errors/calls : " << std::dec << easy_init_errors << "/" << easy_init_calls << llendl; - llinfos_nf << " Current number of curl easy handles: " << std::dec << (easy_init_calls - easy_init_errors - easy_cleanup_calls) << llendl; - llinfos_nf << "========= END OF CURL STATS =========" << llendl; -} - // THREAD-SAFE void handle_multi_error(CURLMcode code) { @@ -1175,6 +1204,7 @@ LLChannelDescriptors const BufferedCurlEasyRequest::sChannels; BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL) { + AICurlInterface::Stats::BufferedCurlEasyRequest_count++; } #define llmaybeerrs lllog(LLApp::isRunning() ? LLError::LEVEL_ERROR : LLError::LEVEL_WARN, NULL, NULL, false, true) @@ -1202,6 +1232,7 @@ BufferedCurlEasyRequest::~BufferedCurlEasyRequest() timed_out(); } } + --AICurlInterface::Stats::BufferedCurlEasyRequest_count; } void BufferedCurlEasyRequest::timed_out(void) diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index d8f7f75ce..85ae9bf95 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -127,6 +127,23 @@ class AICurlNoBody : public AICurlError { // Things defined in this namespace are called from elsewhere in the viewer code. namespace AICurlInterface { +struct Stats { + static LLAtomicU32 easy_calls; + static LLAtomicU32 easy_errors; + static LLAtomicU32 easy_init_calls; + static LLAtomicU32 easy_init_errors; + static LLAtomicU32 easy_cleanup_calls; + static LLAtomicU32 multi_calls; + static LLAtomicU32 multi_errors; + static LLAtomicU32 AICurlEasyRequest_count; + static LLAtomicU32 AICurlEasyRequestStateMachine_count; + static LLAtomicU32 BufferedCurlEasyRequest_count; + static LLAtomicU32 ResponderBase_count; + static LLAtomicU32 ThreadSafeBufferedCurlEasyRequest_count; + + static void print(void); +}; + //----------------------------------------------------------------------------- // Global functions. @@ -221,11 +238,14 @@ class AICurlEasyRequest { // 'new' never returned however and neither the constructor nor destructor of mBufferedCurlEasyRequest is called in this case. // This might throw AICurlNoEasyHandle. AICurlEasyRequest(void) : - mBufferedCurlEasyRequest(new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest) { } + mBufferedCurlEasyRequest(new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest) { AICurlInterface::Stats::AICurlEasyRequest_count++; } public: + // Update stats. + ~AICurlEasyRequest() { --AICurlInterface::Stats::AICurlEasyRequest_count; } + // Used for storing this object in a standard container (see MultiHandle::add_easy_request). - AICurlEasyRequest(AICurlEasyRequest const& orig) : mBufferedCurlEasyRequest(orig.mBufferedCurlEasyRequest) { } + AICurlEasyRequest(AICurlEasyRequest const& orig) : mBufferedCurlEasyRequest(orig.mBufferedCurlEasyRequest) { AICurlInterface::Stats::AICurlEasyRequest_count++; } // For the rest, only allow read operations. AIThreadSafeSimple& operator*(void) const { llassert(mBufferedCurlEasyRequest.get()); return *mBufferedCurlEasyRequest; } @@ -271,11 +291,11 @@ class AICurlEasyRequest { // then it's OK to construct a AICurlEasyRequest from it. // Note that the external AICurlPrivate::BufferedCurlEasyRequestPtr needs its own locking, because // it's not thread-safe in itself. - AICurlEasyRequest(AICurlPrivate::BufferedCurlEasyRequestPtr const& ptr) : mBufferedCurlEasyRequest(ptr) { } + AICurlEasyRequest(AICurlPrivate::BufferedCurlEasyRequestPtr const& ptr) : mBufferedCurlEasyRequest(ptr) { AICurlInterface::Stats::AICurlEasyRequest_count++; } // This one is obviously dangerous. It's for use only in MultiHandle::check_msg_queue. // See also the long comment in BufferedCurlEasyRequest::finalizeRequest with regard to CURLOPT_PRIVATE. - explicit AICurlEasyRequest(AICurlPrivate::ThreadSafeBufferedCurlEasyRequest* ptr) : mBufferedCurlEasyRequest(ptr) { } + explicit AICurlEasyRequest(AICurlPrivate::ThreadSafeBufferedCurlEasyRequest* ptr) : mBufferedCurlEasyRequest(ptr) { AICurlInterface::Stats::AICurlEasyRequest_count++; } }; #define AICurlPrivate DONTUSE_AICurlPrivate diff --git a/indra/llmessage/aicurleasyrequeststatemachine.cpp b/indra/llmessage/aicurleasyrequeststatemachine.cpp index a5c9f9d44..d7babe6f3 100644 --- a/indra/llmessage/aicurleasyrequeststatemachine.cpp +++ b/indra/llmessage/aicurleasyrequeststatemachine.cpp @@ -249,6 +249,7 @@ AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(void) : mTimer(NULL), mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay()) { Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); + AICurlInterface::Stats::AICurlEasyRequestStateMachine_count++; } void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout) @@ -259,5 +260,6 @@ void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout) AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine() { Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); + --AICurlInterface::Stats::AICurlEasyRequestStateMachine_count; } diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index a5bdf8d8a..44dd38a54 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -111,20 +111,8 @@ class HTTPTimeout : public LLRefCount { } // namespace curlthread -struct Stats { - static LLAtomicU32 easy_calls; - static LLAtomicU32 easy_errors; - static LLAtomicU32 easy_init_calls; - static LLAtomicU32 easy_init_errors; - static LLAtomicU32 easy_cleanup_calls; - static LLAtomicU32 multi_calls; - static LLAtomicU32 multi_errors; - - static void print(void); -}; - void handle_multi_error(CURLMcode code); -inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; } +inline CURLMcode check_multi_code(CURLMcode code) { AICurlInterface::Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; } bool curlThreadIsRunning(void); void wakeUpCurlThread(void); @@ -248,7 +236,7 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven // Always first call setErrorBuffer()! static inline CURLcode check_easy_code(CURLcode code) { - Stats::easy_calls++; + AICurlInterface::Stats::easy_calls++; if (code != CURLE_OK) handle_easy_error(code); return code; @@ -511,9 +499,11 @@ class ThreadSafeBufferedCurlEasyRequest : public AIThreadSafeSimple