From 34e0398ddf5f1d61fdf3a6d4875a40579f8e864a Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 31 May 2013 19:52:23 +0200 Subject: [PATCH 1/4] Fix of issue 855 #12 second image. This should fix 'Received 302 (Moved Temporarily) for responder "AgentStateResponder" which has no followRedir(). Some responders want to deal with redirections themselves, I checked if this (new, pathfinder related) responder wants that in viewer-release, but it doesn't. Turning this on requires to also keep track of cookies, so it's a bit slower and therefore left at the old default: to not let curl follow redirections. Optionally we would turn it on by default and explicitely off for those responders that want to deal with 302's themselves and for those that really don't need it and are used most heavily. --- indra/newview/llpathfindingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 783c728c0..7e5bec546 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -165,6 +165,7 @@ public: /*virtual*/ void result(const LLSD &pContent); /*virtual*/ void error(U32 pStatus, const std::string& pReason); + /*virtual*/ bool followRedir(void) const { return true; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return agentStateResponder_timeout; } /*virtual*/ char const* getName(void) const { return "AgentStateResponder"; } From 5c05a04a2c1664c469ea45d3badb3416fb32fa30 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 1 Jun 2013 13:32:55 +0200 Subject: [PATCH 2/4] Fix of 'LLError::NoClassInfo::~AIFilePicker: Calling AIFilePicker::~AIFilePicker()' --- indra/newview/statemachine/aifilepicker.h | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/statemachine/aifilepicker.h b/indra/newview/statemachine/aifilepicker.h index 0058ea2f0..5c6512899 100644 --- a/indra/newview/statemachine/aifilepicker.h +++ b/indra/newview/statemachine/aifilepicker.h @@ -151,6 +151,7 @@ new AIFilePicker // Objects of this type can be reused multiple times, see // also the documentation of AIStateMachine. class AIFilePicker : public AIStateMachine { + LOG_CLASS(AIFilePicker); protected: // The base class of this state machine. typedef AIStateMachine direct_base_type; From 98badb94da1683470d97ce1694abda8ea687eb05 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 1 Jun 2013 16:14:32 +0200 Subject: [PATCH 3/4] Add AIHTTPView, a HTTP Debug Console - press Ctrl-Shift-7 --- indra/llmessage/aicurl.h | 3 + indra/llmessage/aicurlperservice.cpp | 12 +- indra/llmessage/aicurlperservice.h | 35 ++- indra/llmessage/aicurlprivate.h | 3 + indra/llmessage/aicurlthread.cpp | 17 +- indra/llui/llcontainerview.cpp | 3 +- indra/llui/llcontainerview.h | 4 +- indra/newview/CMakeLists.txt | 2 + indra/newview/aihttpview.cpp | 311 +++++++++++++++++++++++++++ indra/newview/aihttpview.h | 73 +++++++ indra/newview/lldebugview.cpp | 12 ++ indra/newview/llviewermenu.cpp | 10 + 12 files changed, 471 insertions(+), 14 deletions(-) create mode 100644 indra/newview/aihttpview.cpp create mode 100644 indra/newview/aihttpview.h diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index d15c72cd8..6249db171 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -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); diff --git a/indra/llmessage/aicurlperservice.cpp b/indra/llmessage/aicurlperservice.cpp index ff452c358..8b00d32b6 100644 --- a/indra/llmessage/aicurlperservice.cpp +++ b/indra/llmessage/aicurlperservice.cpp @@ -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--; } diff --git a/indra/llmessage/aicurlperservice.h b/indra/llmessage/aicurlperservice.h index f50c1f393..7c53a06ab 100644 --- a/indra/llmessage/aicurlperservice.h +++ b/indra/llmessage/aicurlperservice.h @@ -43,12 +43,15 @@ #include #include #include +#include +#include #include #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 BufferedCurlEasyRequestPtr; +} // namespace AICurlPrivate + // AIPerService objects are created by the curl thread and destructed by the main thread. // We need locking. typedef AIThreadSafeSimpleDC threadsafe_PerService; @@ -66,8 +71,6 @@ typedef AIAccessConst PerService_crat; typedef AIAccess PerService_rat; typedef AIAccess 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 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 instance_map_type; typedef AIThreadSafeSimpleDC threadsafe_instance_map_type; typedef AIAccess instance_map_rat; typedef AIAccess instance_map_wat; + private: static threadsafe_instance_map_type sInstanceMap; // Map of AIPerService instances with the hostname as key. friend class AIThreadSafeSimpleDC; // 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 + 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 +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 > 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 diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index aa5a1ba7b..af8b6b267 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -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) diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index d27e755c6..4a9c9198c 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -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; diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp index 04ede8942..f9ee54e9f 100644 --- a/indra/llui/llcontainerview.cpp +++ b/indra/llui/llcontainerview.cpp @@ -51,6 +51,7 @@ LLContainerView::LLContainerView(const LLContainerView::Params& p) { mCollapsible = TRUE; mScrollContainer = NULL; + mRectAlpha = 0.25; } LLContainerView::~LLContainerView() @@ -100,7 +101,7 @@ void LLContainerView::draw() { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, mRectAlpha)); } // Draw the label diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h index be340581d..70d994f87 100644 --- a/indra/llui/llcontainerview.h +++ b/indra/llui/llcontainerview.h @@ -75,17 +75,17 @@ public: void setDisplayChildren(const BOOL displayChildren); BOOL getDisplayChildren() { return mDisplayChildren; } void setScrollContainer(LLScrollContainer* scroll); + void setRectAlpha(F32 alpha) { mRectAlpha = alpha; } private: LLScrollContainer* mScrollContainer; void arrange(S32 width, S32 height, BOOL called_from_parent = TRUE); BOOL mShowLabel; - + F32 mRectAlpha; protected: BOOL mDisplayChildren; std::string mLabel; public: BOOL mCollapsible; - }; #endif // LL_CONTAINERVIEW_ diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8a0406c18..78b3c9ddb 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -79,6 +79,7 @@ include_directories( set(viewer_SOURCE_FILES NACLantispam.cpp + aihttpview.cpp aoremotectrl.cpp ascentfloatercontactgroups.cpp ascentkeyword.cpp @@ -575,6 +576,7 @@ set(viewer_HEADER_FILES ViewerInstall.cmake NACLantispam.h + aihttpview.h aoremotectrl.h ascentfloatercontactgroups.h ascentkeyword.h diff --git a/indra/newview/aihttpview.cpp b/indra/newview/aihttpview.cpp new file mode 100644 index 000000000..caa2fc24d --- /dev/null +++ b/indra/newview/aihttpview.cpp @@ -0,0 +1,311 @@ +/** + * @file aihttpview.cpp + * @brief Definition of class AIHTTPView. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 28/05/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "llviewerprecompiledheaders.h" +#include "aihttpview.h" +#include "llrect.h" +#include "llerror.h" +#include "aicurlperservice.h" +#include "llviewerstats.h" +#include "llfontgl.h" +#include "aihttptimeout.h" + +AIHTTPView* gHttpView = NULL; +static S32 sLineHeight; + +// Forward declaration. +namespace AICurlInterface { + size_t getHTTPBandwidth(void); + U32 getNumHTTPAdded(void); + U32 getMaxHTTPAdded(void); +} // namespace AICurlInterface + +//============================================================================= + + //PerService_crat per_service_r(*service.second); +class AIServiceBar : public LLView +{ + private: + AIHTTPView* mHTTPView; + std::string mName; + AIPerServicePtr mPerService; + + public: + AIServiceBar(AIHTTPView* httpview, AIPerService::instance_map_type::value_type const& service) + : LLView("aiservice bar", LLRect(), FALSE), mHTTPView(httpview), mName(service.first), mPerService(service.second) { } + + /*virtual*/ void draw(void); + /*virtual*/ LLRect getRequiredRect(void); +}; + +int const mc_col = number_of_capability_types; // Maximum connections column. +int const bw_col = number_of_capability_types + 1; // Bandwidth column. + +void AIServiceBar::draw() +{ + LLColor4 text_color = LLColor4::white; + F32 height = getRect().getHeight(); + U32 start = 4; + LLFontGL::getFontMonospace()->renderUTF8(mName, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(mName); + std::string text; + PerService_rat per_service_r(*mPerService); + for (int col = 0; col < number_of_capability_types; ++col) + { + AIPerService::CapabilityType& ct(per_service_r->mCapabilityType[col]); + start = mHTTPView->updateColumn(col, start); + if (col < 2) + { + text = llformat(" | %hu-%hu-%lu,{%hu,%u}/%u", ct.mApprovedRequests, ct.mQueuedCommands, ct.mQueuedRequests.size(), ct.mAdded, ct.mDownloading, ct.mMaxPipelinedRequests); + } + else + { + text = llformat(" | --%hu-%lu,{%hu,%u}", ct.mQueuedCommands, ct.mQueuedRequests.size(), ct.mAdded, ct.mDownloading); + } + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + } + start = mHTTPView->updateColumn(mc_col, start); + text = llformat(" | %d/%d", per_service_r->mTotalAdded, per_service_r->mConcurrectConnections); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + start = mHTTPView->updateColumn(bw_col, start); + size_t bandwidth = per_service_r->bandwidth().truncateData(AIHTTPView::getTime_40ms()); + size_t max_bandwidth = mHTTPView->mMaxBandwidthPerService; + text = " | "; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + text = llformat("%lu", bandwidth / 125); + LLColor4 color = (bandwidth > max_bandwidth) ? LLColor4::red : ((bandwidth > max_bandwidth * .75f) ? LLColor4::yellow : text_color); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + text = llformat("/%lu", max_bandwidth / 125); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); +} + +LLRect AIServiceBar::getRequiredRect(void) +{ + LLRect rect; + rect.mTop = sLineHeight; + return rect; +} + +//============================================================================= + +static int const number_of_header_lines = 2; + +class AIGLHTTPHeaderBar : public LLView +{ + public: + AIGLHTTPHeaderBar(std::string const& name, AIHTTPView* httpview) : + LLView(name, FALSE), mHTTPView(httpview) + { + sLineHeight = llround(LLFontGL::getFontMonospace()->getLineHeight()); + setRect(LLRect(0, 0, 200, sLineHeight * number_of_header_lines)); + } + + /*virtual*/ void draw(void); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ LLRect getRequiredRect(void); + + private: + AIHTTPView* mHTTPView; +}; + +void AIGLHTTPHeaderBar::draw(void) +{ + S32 const v_offset = -1; // Offset from the bottom. Move header one pixel down. + S32 const h_offset = 4; + + LLGLSUIDefault gls_ui; + + LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); + std::string text; + + // First header line. + F32 height = v_offset + sLineHeight * number_of_header_lines; + text = "HTTP console -- [approved]-commandQ-curlQ,{added,downloading}[/max]"; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, h_offset, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); + text = " | Added/Max"; + U32 start = mHTTPView->updateColumn(mc_col, 100); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + text = " | Tot/Max BW (kbit/s)"; + start = mHTTPView->updateColumn(bw_col, start); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP); + mHTTPView->setWidth(start + LLFontGL::getFontMonospace()->getWidth(text) + h_offset); + + // Second header line. + height -= sLineHeight; + start = h_offset; + text = "Service (host:port)"; + static char const* caption[number_of_capability_types] = { + " | Textures", " | Inventory", " | Mesh", " | Other" + }; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + for (int col = 0; col < number_of_capability_types; ++col) + { + start = mHTTPView->updateColumn(col, start); + text = caption[col]; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + } + start = mHTTPView->updateColumn(mc_col, start); + text = llformat(" | %u/%u", AICurlInterface::getNumHTTPAdded(), AICurlInterface::getMaxHTTPAdded()); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + + // This bandwidth is averaged over 1 seconds (in bytes/s). + size_t const bandwidth = AICurlInterface::getHTTPBandwidth(); + size_t const max_bandwidth = AIPerService::getHTTPThrottleBandwidth125(); + mHTTPView->mMaxBandwidthPerService = max_bandwidth * AIPerService::throttleFraction(); + LLColor4 color = (bandwidth > max_bandwidth) ? LLColor4::red : ((bandwidth > max_bandwidth * .75f) ? LLColor4::yellow : text_color); + color[VALPHA] = text_color[VALPHA]; + start = mHTTPView->updateColumn(bw_col, start); + text = " | "; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + text = llformat("%lu", bandwidth / 125); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, color, LLFontGL::LEFT, LLFontGL::TOP); + start += LLFontGL::getFontMonospace()->getWidth(text); + text = llformat("/%lu", max_bandwidth / 125); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP); +} + +BOOL AIGLHTTPHeaderBar::handleMouseDown(S32 x, S32 y, MASK mask) +{ + return FALSE; +} + +LLRect AIGLHTTPHeaderBar::getRequiredRect() +{ + LLRect rect; + rect.mTop = sLineHeight * number_of_header_lines; + return rect; +} + +//============================================================================= + +AIHTTPView::AIHTTPView(AIHTTPView::Params const& p) : + LLContainerView(p), mGLHTTPHeaderBar(NULL), mWidth(200) +{ + setVisible(FALSE); + setRectAlpha(0.5); +} + +AIHTTPView::~AIHTTPView() +{ + delete mGLHTTPHeaderBar; + mGLHTTPHeaderBar = NULL; +} + +U32 AIHTTPView::updateColumn(int col, U32 start) +{ + llassert(col <= mStartColumn.size()); + if (col == mStartColumn.size()) + { + mStartColumn.push_back(start); + } + else if (mStartColumn[col] < start) + { + mStartColumn[col] = start; + } + return mStartColumn[col]; +} + +U64 AIHTTPView::sTime_40ms; + +struct KillView +{ + void operator()(LLView* viewp) + { + viewp->getParent()->removeChild(viewp); + viewp->die(); + } +}; + +struct CreateServiceBar +{ + AIHTTPView* mHTTPView; + + CreateServiceBar(AIHTTPView* httpview) : mHTTPView(httpview) { } + + void operator()(AIPerService::instance_map_type::value_type const& service) + { + AIServiceBar* service_bar = new AIServiceBar(mHTTPView, service); + mHTTPView->addChild(service_bar); + mHTTPView->mServiceBars.push_back(service_bar); + } +}; + +void AIHTTPView::draw() +{ + for_each(mServiceBars.begin(), mServiceBars.end(), KillView()); + mServiceBars.clear(); + + if (mGLHTTPHeaderBar) + { + removeChild(mGLHTTPHeaderBar); + mGLHTTPHeaderBar->die(); + } + + CreateServiceBar functor(this); + AIPerService::copy_forEach(functor); + + sTime_40ms = get_clock_count() * AICurlPrivate::curlthread::HTTPTimeout::sClockWidth_40ms; + + mGLHTTPHeaderBar = new AIGLHTTPHeaderBar("gl httpheader bar", this); + addChild(mGLHTTPHeaderBar); + + reshape(mWidth, getRect().getHeight(), TRUE); + + for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) + { + LLView* viewp = *child_iter; + if (viewp->getRect().mBottom < 0) + { + viewp->setVisible(FALSE); + } + } + + LLContainerView::draw(); +} + +BOOL AIHTTPView::handleMouseUp(S32 x, S32 y, MASK mask) +{ + return FALSE; +} + +BOOL AIHTTPView::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + return FALSE; +} + diff --git a/indra/newview/aihttpview.h b/indra/newview/aihttpview.h new file mode 100644 index 000000000..f63bc5a61 --- /dev/null +++ b/indra/newview/aihttpview.h @@ -0,0 +1,73 @@ +/** + * @file aihttpview.h + * @brief Declaration for AIHTTPView. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 28/05/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIHTTPVIEW_H +#define AIHTTPVIEW_H + +#include "llcontainerview.h" +#include + +class AIGLHTTPHeaderBar; +class AIServiceBar; +struct CreateServiceBar; + +class AIHTTPView : public LLContainerView +{ + friend class AIGLHTTPHeaderBar; + friend class AIServiceBar; + friend struct CreateServiceBar; + + public: + AIHTTPView(AIHTTPView::Params const& p); + ~AIHTTPView(); + + /*virtual*/ void draw(void); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + + U32 updateColumn(int col, U32 start); + void setWidth(S32 width) { mWidth = width; } + + private: + AIGLHTTPHeaderBar* mGLHTTPHeaderBar; + std::vector mServiceBars; + std::vector mStartColumn; + size_t mMaxBandwidthPerService; + S32 mWidth; + + static U64 sTime_40ms; + + public: + static U64 getTime_40ms(void) { return sTime_40ms; } +}; + +extern AIHTTPView *gHttpView; + +#endif // AIHTTPVIEW_H diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index 92dc5dffa..e1451a411 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -39,6 +39,7 @@ #include "llfasttimerview.h" #include "llconsole.h" #include "lltextureview.h" +#include "aihttpview.h" #include "llresmgr.h" #include "imageids.h" #include "llvelocitybar.h" @@ -93,6 +94,16 @@ LLDebugView::LLDebugView(const std::string& name, const LLRect &rect) addChild(gTextureView); //gTextureView->reshape(r.getWidth(), r.getHeight(), TRUE); + r.set(150, rect.getHeight() - 50, 870, 100); + AIHTTPView::Params hvp; + hvp.name("gHttpView"); + hvp.rect(r); + hvp.visible(false); + gHttpView = LLUICtrlFactory::create(hvp); + //gHttpView->setFollowsBottom(); + //gHttpView->setFollowsLeft(); + addChild(gHttpView); + if(gAuditTexture) { r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100); @@ -129,6 +140,7 @@ LLDebugView::~LLDebugView() // These have already been deleted. Fix the globals appropriately. gDebugView = NULL; gTextureView = NULL; + gHttpView = NULL; gTextureSizeView = NULL; gTextureCategoryView = NULL; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 52799fdf4..8c06890ab 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -221,6 +221,8 @@ void handle_test_load_url(void*); // // Evil hackish imported globals +class AIHTTPView; + //extern BOOL gHideSelectedObjects; //extern BOOL gAllowSelectAvatar; //extern BOOL gDebugAvatarRotation; @@ -229,6 +231,7 @@ extern BOOL gDebugWindowProc; extern BOOL gDebugTextEditorTips; extern BOOL gShowOverlayTitle; extern BOOL gOcclusionCull; +extern AIHTTPView* gHttpView; // // Globals // @@ -817,6 +820,13 @@ void init_client_menu(LLMenuGL* menu) '6', MASK_CONTROL|MASK_SHIFT ) ); } + sub->addChild(new LLMenuItemCheckGL("HTTP Console", + &toggle_visibility, + NULL, + &get_visibility, + (void*)gHttpView, + '7', MASK_CONTROL|MASK_SHIFT ) ); + sub->addChild(new LLMenuItemCheckGL("Region Debug Console", handle_singleton_toggle, NULL, handle_singleton_check,NULL,'`', MASK_CONTROL|MASK_SHIFT)); sub->addChild(new LLMenuItemCheckGL("Fast Timers", From 24fb76907d7cbbcdf606837b34180f5da5ea7dad Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 1 Jun 2013 16:37:02 +0200 Subject: [PATCH 4/4] Compile fix --- indra/newview/statemachine/aidirpicker.h | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/statemachine/aidirpicker.h b/indra/newview/statemachine/aidirpicker.h index 452f42b3e..484a8e650 100644 --- a/indra/newview/statemachine/aidirpicker.h +++ b/indra/newview/statemachine/aidirpicker.h @@ -43,6 +43,7 @@ // Objects of this type can be reused multiple times, see // also the documentation of AIStateMachine. class AIDirPicker : protected AIFilePicker { + LOG_CLASS(AIDirPicker); public: // Allow to pass the arguments to open upon creation. //