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/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"; } 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", 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. // 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;