diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index eb45729b9..53e890040 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -22,6 +22,7 @@ include_directories(
)
set(llmessage_SOURCE_FILES
+ aiaverage.cpp
aicurl.cpp
aicurleasyrequeststatemachine.cpp
aicurlperservice.cpp
@@ -109,6 +110,7 @@ set(llmessage_SOURCE_FILES
set(llmessage_HEADER_FILES
CMakeLists.txt
+ aiaverage.h
aicurl.h
aicurleasyrequeststatemachine.h
aicurlperservice.h
diff --git a/indra/llmessage/aiaverage.cpp b/indra/llmessage/aiaverage.cpp
new file mode 100644
index 000000000..10aafd852
--- /dev/null
+++ b/indra/llmessage/aiaverage.cpp
@@ -0,0 +1,81 @@
+/**
+ * @file aiaverage.cpp
+ * @brief Implementation of AIAverage
+ *
+ * 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.
+ *
+ * 11/04/2013
+ * Initial version, written by Aleric Inglewood @ SL
+ */
+
+#include "sys.h"
+#include "aiaverage.h"
+#include "llerror.h" // llassert
+
+void AIAverage::cleanup(U64 clock_tick)
+{
+ // This expression can fail because the curl thread caches the time in
+ // sTime_10ms for the duration of an entire loop. Therefore, the time can
+ // go into the next 40ms and a texture fetch worker thread might call
+ // cleanup() with that time, setting mCurrentClock to a value (one)
+ // larger than sTime_10ms / 4. Next, the curl thread can continue to call
+ // this function with the smaller value; in that case just add the new
+ // data to the current bucket.
+ //
+ // Or, this is just the one-time initialization that happens the first
+ // time this is called. In that case initialize just mCurrentClock:
+ // the rest is already initialized upon construction.
+ if (LL_LIKELY(clock_tick > mCurrentClock))
+ {
+ // Advance to the next bucket.
+ ++mCurrentBucket;
+ mCurrentBucket %= mNrOfBuckets;
+ // Initialize the new bucket.
+ mData[mCurrentBucket].time = clock_tick;
+ // Clean up old buckets.
+ U64 old_time = clock_tick - mNrOfBuckets;
+ if (LL_UNLIKELY(mTail == mCurrentBucket) || // Extremely unlikely: only happens when data was added EVERY clock tick for the past mNrOfBuckets clock ticks.
+ mData[mTail].time <= old_time)
+ {
+ do
+ {
+ mSum -= mData[mTail].sum;
+ mN -= mData[mTail].n;
+ mData[mTail].sum = 0;
+ mData[mTail].n = 0;
+ ++mTail;
+ if (LL_UNLIKELY(mTail == mNrOfBuckets))
+ {
+ mTail = 0;
+ }
+ }
+ while (mData[mTail].time <= old_time);
+ }
+ // This was set to zero when mTail passed this point (likely not this call, but a few calls ago).
+ llassert(mData[mCurrentBucket].sum == 0 &&
+ mData[mCurrentBucket].n == 0);
+ }
+ mCurrentClock = clock_tick;
+ return;
+}
+
diff --git a/indra/llmessage/aiaverage.h b/indra/llmessage/aiaverage.h
new file mode 100644
index 000000000..f8f344df6
--- /dev/null
+++ b/indra/llmessage/aiaverage.h
@@ -0,0 +1,108 @@
+/**
+ * @file aiaverage.h
+ * @brief Definition of class AIAverage
+ *
+ * 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.
+ *
+ * 11/04/2013
+ * Initial version, written by Aleric Inglewood @ SL
+ */
+
+#ifndef AIAVERAGE_H
+#define AIAVERAGE_H
+
+#include "llpreprocessor.h"
+#include "stdtypes.h" // U32, U64
+#include "llthread.h" // LLMutex
+#include // size_t
+#include
+
+class AIAverage {
+ private:
+ struct Data {
+ U32 sum; // Accumulated sum of the 'n' passed to operator()(size_t n, U64 clock_tick) with clock_tick == time.
+ U32 n; // The number of calls to operator().
+ U64 time; // The clock_tick as passed to operator()(size_t n, U64 clock_tick) that sum corresponds to.
+ };
+
+ U64 mCurrentClock; // The current (last) time that operator() was called with, or -1 when not initialized.
+ int mTail; // The oldest bucket with still valid data.
+ int mCurrentBucket; // The bucket that corresponds to mCurrentClock.
+ size_t mSum; // The sum of all the 'n' passed to operator()(size_t n, U64 clock_tick) for all passed mNrOfBuckets time units.
+ U32 mN; // The number of calls to operator().
+ int const mNrOfBuckets; // Size of mData.
+ std::vector mData; // The buckets.
+ LLMutex mLock; // Mutex for all of the above data.
+
+ public:
+ AIAverage(int number_of_buckets) : mCurrentClock(~(U64)0), mTail(0), mCurrentBucket(0), mSum(0), mN(0), mNrOfBuckets(number_of_buckets), mData(number_of_buckets)
+ {
+ // Fill mData with all zeroes (much faster than adding a constructor to Data).
+ std::memset(&*mData.begin(), 0, number_of_buckets * sizeof(Data));
+ }
+ size_t addData(U32 n, U64 clock_tick)
+ {
+ DoutEntering(dc::curl, "AIAverage::addData(" << n << ", " << clock_tick << ")");
+ mLock.lock();
+ if (LL_UNLIKELY(clock_tick != mCurrentClock))
+ {
+ cleanup(clock_tick);
+ }
+ mSum += n;
+ mN += 1;
+ mData[mCurrentBucket].sum += n;
+ mData[mCurrentBucket].n += 1;
+ size_t sum = mSum;
+ mLock.unlock();
+ Dout(dc::curl, "Current sum: " << sum << ", average: " << (sum / mN));
+ return sum;
+ }
+ size_t truncateData(U64 clock_tick)
+ {
+ mLock.lock();
+ if (clock_tick != mCurrentClock)
+ {
+ cleanup(clock_tick);
+ }
+ size_t sum = mSum;
+ mLock.unlock();
+ return sum;
+ }
+ double getAverage(double avg_no_data)
+ {
+ mLock.lock();
+ double avg = mSum;
+ llassert(mN != 0 || mSum == 0);
+ if (LL_UNLIKELY(mN == 0))
+ avg = avg_no_data;
+ else
+ avg /= mN;
+ mLock.unlock();
+ return avg;
+ }
+
+ private:
+ void cleanup(U64 clock_tick);
+};
+
+#endif // AIAVERAGE
diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp
index 651e0e9eb..93153951a 100644
--- a/indra/llmessage/aicurl.cpp
+++ b/indra/llmessage/aicurl.cpp
@@ -1267,8 +1267,9 @@ static int const HTTP_REDIRECTS_DEFAULT = 10;
LLChannelDescriptors const BufferedCurlEasyRequest::sChannels;
LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex;
bool BufferedCurlEasyRequest::sShuttingDown = false;
+AIAverage BufferedCurlEasyRequest::sHTTPBandwidth(25);
-BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
+BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mTotalRawBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER)
{
AICurlInterface::Stats::BufferedCurlEasyRequest_count++;
}
@@ -1332,7 +1333,7 @@ void BufferedCurlEasyRequest::resetState(void)
mOutput.reset();
mInput.reset();
mRequestTransferedBytes = 0;
- mResponseTransferedBytes = 0;
+ mTotalRawBytes = 0;
mBufferEventsTarget = NULL;
mStatus = HTTP_INTERNAL_ERROR_OTHER;
}
diff --git a/indra/llmessage/aicurlperservice.h b/indra/llmessage/aicurlperservice.h
index cf4d8ba71..8cd310f40 100644
--- a/indra/llmessage/aicurlperservice.h
+++ b/indra/llmessage/aicurlperservice.h
@@ -45,6 +45,7 @@
#include
- DebugStatModeTexture
+ DebugStatModeHTTPTexture
+
+ DebugStatModeUDPTexture