diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h
index 5c46f6a79651ecd4b6e117342b0576575623f26a..4e25001fff720c54875df8eb5028640b83878686 100644
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -167,48 +167,34 @@ const U32	MAXADDRSTR		= 17;		// 123.567.901.345 = 15 chars + \0 + 1 for good luc
 //
 // defined for U16, U32, U64, S16, S32, S64, :
 //   llclampb(a)     // clamps a to [0 .. 255]
-//   				   
-
-template <typename T1, typename T2> 
-inline auto llmax(T1 d1, T2 d2)
-{
-	return (d1 > d2) ? d1 : d2;
-}
-
-template <typename T1, typename T2, typename T3> 
-inline auto llmax(T1 d1, T2 d2, T3 d3)
-{
-	auto r = llmax(d1,d2);
-	return llmax(r, d3);
-}
+//
 
-template <typename T1, typename T2, typename T3, typename T4> 
-inline auto llmax(T1 d1, T2 d2, T3 d3, T4 d4)
+// recursion tail
+template <typename T>
+inline auto llmax(T data)
 {
-	auto r1 = llmax(d1,d2);
-	auto r2 = llmax(d3,d4);
-	return llmax(r1, r2);
+    return data;
 }
 
-template <typename T1, typename T2> 
-inline auto llmin(T1 d1, T2 d2)
+template <typename T0, typename T1, typename... Ts> 
+inline auto llmax(T0 d0, T1 d1, Ts... rest)
 {
-	return (d1 < d2) ? d1 : d2;
+    auto maxrest = llmax(d1, rest...);
+    return (d0 > maxrest)? d0 : maxrest;
 }
 
-template <typename T1, typename T2, typename T3> 
-inline auto llmin(T1 d1, T2 d2, T3 d3)
+// recursion tail
+template <typename T>
+inline auto llmin(T data)
 {
-	auto r = llmin(d1,d2);
-	return (r < d3 ? r : d3);
+    return data;
 }
 
-template <typename T1, typename T2, typename T3, typename T4> 
-inline auto llmin(T1 d1, T2 d2, T3 d3, T4 d4)
+template <typename T0, typename T1, typename... Ts> 
+inline auto llmin(T0 d0, T1 d1, Ts... rest)
 {
-	auto r1 = llmin(d1,d2);
-	auto r2 = llmin(d3,d4);
-	return llmin(r1, r2);
+    auto minrest = llmin(d1, rest...);
+    return (d0 < minrest) ? d0 : minrest;
 }
 
 template <typename A, typename MIN, typename MAX> 
diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp
index 9b2a2bab60f48195614aa9d1a16c201681d9f477..0abe817f1ddcd2fc3e37c3b15359069bf7aa385c 100644
--- a/indra/llcommon/llmd5.cpp
+++ b/indra/llcommon/llmd5.cpp
@@ -96,7 +96,7 @@ LLMD5::LLMD5()
 // operation, processing another message block, and updating the
 // context.
 
-void LLMD5::update (const uint1 *input, const size_t input_length) {
+void LLMD5::update (const uint8_t *input, const size_t input_length) {
 
   size_t input_index, buffer_index;
   size_t buffer_space;                // how much space is left in buffer
@@ -189,7 +189,7 @@ void LLMD5::finalize (){
 
   unsigned char bits[8];		/* Flawfinder: ignore */
   size_t index, padLen;
-  static uint1 PADDING[64]={
+  static uint8_t PADDING[64]={
     0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -201,8 +201,8 @@ void LLMD5::finalize (){
   }
 
   // Save number of bits.
-  // Treat count, a uint64_t, as uint4[2].
-  encode (bits, reinterpret_cast<uint4*>(&count), 8);
+  // Treat count, a uint64_t, as uint32_t[2].
+  encode (bits, reinterpret_cast<uint32_t*>(&count), 8);
 
   // Pad out to 56 mod 64.
   index = size_t((count >> 3) & 0x3f);
@@ -412,7 +412,7 @@ Rotation is separate from addition to prevent recomputation.
 // LLMD5 basic transformation. Transforms state based on block.
 void LLMD5::transform (const U8 block[64]){
 
-  uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+  uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
 
   decode (x, block, 64);
 
@@ -496,38 +496,38 @@ void LLMD5::transform (const U8 block[64]){
   state[3] += d;
 
   // Zeroize sensitive information.
-  memset ( (uint1 *) x, 0, sizeof(x));
+  memset ( (uint8_t *) x, 0, sizeof(x));
 
 }
 
 
 
-// Encodes input (UINT4) into output (unsigned char). Assumes len is
+// Encodes input (uint32_t) into output (unsigned char). Assumes len is
 // a multiple of 4.
-void LLMD5::encode (uint1 *output, const uint4 *input, const size_t len) {
+void LLMD5::encode (uint8_t *output, const uint32_t *input, const size_t len) {
 
   size_t i, j;
 
   for (i = 0, j = 0; j < len; i++, j += 4) {
-    output[j]   = (uint1)  (input[i] & 0xff);
-    output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
-    output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
-    output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
+    output[j]   = (uint8_t)  (input[i] & 0xff);
+    output[j+1] = (uint8_t) ((input[i] >> 8) & 0xff);
+    output[j+2] = (uint8_t) ((input[i] >> 16) & 0xff);
+    output[j+3] = (uint8_t) ((input[i] >> 24) & 0xff);
   }
 }
 
 
 
 
-// Decodes input (unsigned char) into output (UINT4). Assumes len is
+// Decodes input (unsigned char) into output (uint32_t). Assumes len is
 // a multiple of 4.
-void LLMD5::decode (uint4 *output, const uint1 *input, const size_t len){
+void LLMD5::decode (uint32_t *output, const uint8_t *input, const size_t len){
 
   size_t i, j;
 
   for (i = 0, j = 0; j < len; i++, j += 4)
-    output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
-      (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
+    output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
+      (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
 }
 
 
diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h
index 8530dc03891d9d9e85d203709b918bfa66cf3fbd..7d6373c20cba51e1eee4cf98ca1344e0e5fb80d1 100644
--- a/indra/llcommon/llmd5.h
+++ b/indra/llcommon/llmd5.h
@@ -67,6 +67,8 @@ documentation and/or software.
 
 */
 
+#include <cstdint>                  // uint32_t et al.
+
 // use for the raw digest output
 const int MD5RAW_BYTES = 16;
 
@@ -75,18 +77,13 @@ const int MD5HEX_STR_SIZE = 33;  // char hex[MD5HEX_STR_SIZE]; with null
 const int MD5HEX_STR_BYTES = 32; // message system fixed size
 
 class LL_COMMON_API LLMD5 {
-// first, some types:
-  typedef unsigned       int uint4; // assumes integer is 4 words long
-  typedef unsigned short int uint2; // assumes short integer is 2 words long
-  typedef unsigned      char uint1; // assumes char is 1 word long
-
 // how many bytes to grab at a time when checking files
   static const int BLOCK_LEN;
 
 public:
 // methods for controlled operation:
   LLMD5              ();  // simple initializer
-  void  update     (const uint1 *input, const size_t input_length);
+  void  update     (const uint8_t *input, const size_t input_length);
   void  update     (std::istream& stream);
   void  update     (FILE *file);
   void  update     (const std::string& str);
@@ -109,19 +106,19 @@ class LL_COMMON_API LLMD5 {
 
 
 // next, the private data:
-  uint4 state[4];
+  uint32_t state[4];
   uint64_t count;     // number of *bits*, mod 2^64
-  uint1 buffer[64];   // input buffer
-  uint1 digest[16];
-  uint1 finalized;
+  uint8_t buffer[64];   // input buffer
+  uint8_t digest[16];
+  uint8_t finalized;
 
 // last, the private methods, mostly static:
   void init             ();               // called by all constructors
-  void transform        (const uint1 *buffer);  // does the real update work.  Note 
+  void transform        (const uint8_t *buffer);  // does the real update work.  Note 
                                           // that length is implied to be 64.
 
-  static void encode    (uint1 *dest, const uint4 *src, const size_t length);
-  static void decode    (uint4 *dest, const uint1 *src, const size_t length);
+  static void encode    (uint8_t *dest, const uint32_t *src, const size_t length);
+  static void decode    (uint32_t *dest, const uint8_t *src, const size_t length);
 
 };
 
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index a14a6b5b1bc33e8fe2d45f595f73ccb6bcee2c47..046523dbb12b115a8987a8694f96b56ee106055e 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -143,7 +143,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes)
 		// byte. We could store one if needed, since even the incremented
 		// inbuf won't exceed sizeof(hdr_buf)-1, but there's no need.
 	}
-	std::string header{ hdr_buf, inbuf };
+	std::string header{ hdr_buf, static_cast<std::string::size_type>(inbuf) };
 	if (str.fail())
 	{
 		str.clear();
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index a8dcc5226afafd0401bd7eb7a7e93447421123fb..bb3d667a426baabcb63c46d71664bdf5e489ba0a 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -577,10 +577,12 @@ S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
 // PeriodicRecording
 ///////////////////////////////////////////////////////////////////////
 
-PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state) 
+PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) 
 :	mAutoResize(num_periods == 0),
 	mCurPeriod(0),
 	mNumRecordedPeriods(0),
+	// This guarantee that mRecordingPeriods cannot be empty is essential for
+	// code in several methods.
 	mRecordingPeriods(num_periods ? num_periods : 1)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
@@ -596,18 +598,19 @@ PeriodicRecording::~PeriodicRecording()
 
 void PeriodicRecording::nextPeriod()
 {
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (mAutoResize)
 	{
 		mRecordingPeriods.push_back(Recording());
 	}
 
 	Recording& old_recording = getCurRecording();
-	mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size();
+	inci(mCurPeriod);
 	old_recording.splitTo(getCurRecording());
 
-	mNumRecordedPeriods = mRecordingPeriods.empty()? 0 :
-		llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1);
+	// Since mRecordingPeriods always has at least one entry, we can always
+	// safely subtract 1 from its size().
+	mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1);
 }
 
 void PeriodicRecording::appendRecording(Recording& recording)
@@ -620,31 +623,29 @@ void PeriodicRecording::appendRecording(Recording& recording)
 
 void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 {
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	if (other.mRecordingPeriods.empty()) return;
 
 	getCurRecording().update();
 	other.getCurRecording().update();
-	
-	const auto other_recording_slots = other.mRecordingPeriods.size();
+
 	const auto other_num_recordings = other.getNumRecordedPeriods();
 	const auto other_current_recording_index = other.mCurPeriod;
-	const auto other_oldest_recording_index = (other_current_recording_index + other_recording_slots - other_num_recordings) % other_recording_slots;
+	const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings);
 
 	// append first recording into our current slot
 	getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]);
 
 	// from now on, add new recordings for everything after the first
-	auto other_index = (other_oldest_recording_index + 1) % other_recording_slots;
+	auto other_index = other.nexti(other_oldest_recording_index);
 
 	if (mAutoResize)
 	{
 		// push back recordings for everything in the middle
-		auto other_index = (other_oldest_recording_index + 1) % other_recording_slots;
 		while (other_index != other_current_recording_index)
 		{
 			mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]);
-			other_index = (other_index + 1) % other_recording_slots;
+			other.inci(other_index);
 		}
 
 		// add final recording, if it wasn't already added as the first
@@ -653,36 +654,25 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 			mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]);
 		}
 
-		mCurPeriod = mRecordingPeriods.empty()? 0 : mRecordingPeriods.size() - 1;
+		// mRecordingPeriods is never empty()
+		mCurPeriod = mRecordingPeriods.size() - 1;
 		mNumRecordedPeriods = mCurPeriod;
 	}
 	else
 	{
-		S32 num_to_copy = llmin((S32)mRecordingPeriods.size(), (S32)other_num_recordings);
-
-		std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() + other_index ;
-		std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod;
-
+		auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings);
 		// already consumed the first recording from other, so start counting at 1
-		for(S32 i = 1; i < num_to_copy; i++)
+		for (size_t n = 1, srci = other_index, dsti = mCurPeriod;
+			 n < num_to_copy;
+			 ++n, other.inci(srci), inci(dsti))
 		{
-			*dest_it = *src_it;
-
-			if (++src_it == other.mRecordingPeriods.end())
-			{
-				src_it = other.mRecordingPeriods.begin();
-			}
-
-			if (++dest_it == mRecordingPeriods.end())
-			{
-				dest_it = mRecordingPeriods.begin();
-			}
+			mRecordingPeriods[dsti] = other.mRecordingPeriods[srci];
 		}
-		
+
 		// want argument to % to be positive, otherwise result could be negative and thus out of bounds
 		llassert(num_to_copy >= 1);
 		// advance to last recording period copied, and make that our current period
-		mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size();
+		inci(mCurPeriod, num_to_copy - 1);
 		mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1);
 	}
 
@@ -694,13 +684,11 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 
 F64Seconds PeriodicRecording::getDuration() const
 {
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	F64Seconds duration;
-	auto num_periods = mRecordingPeriods.size();
-	for (size_t i = 1; i <= num_periods; i++)
+	for (size_t n = 0; n < mRecordingPeriods.size(); ++n)
 	{
-		auto index = (mCurPeriod + num_periods - i) % num_periods;
-		duration += mRecordingPeriods[index].getDuration();
+		duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration();
 	}
 	return duration;
 }
@@ -737,16 +725,14 @@ const Recording& PeriodicRecording::getCurRecording() const
 
 Recording& PeriodicRecording::getPrevRecording( size_t offset )
 {
-	auto num_periods = mRecordingPeriods.size();
-	offset = llclamp(offset, 0, num_periods - 1);
-	return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
+	// reuse const implementation, but return non-const reference
+	return const_cast<Recording&>(
+		const_cast<const PeriodicRecording*>(this)->getPrevRecording(offset));
 }
 
 const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const
 {
-	auto num_periods = mRecordingPeriods.size();
-	offset = llclamp(offset, 0, num_periods - 1);
-	return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
+	return mRecordingPeriods[previ(mCurPeriod, offset)];
 }
 
 void PeriodicRecording::handleStart()
@@ -789,14 +775,14 @@ void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
 	getCurRecording().splitTo(other.getCurRecording());
 }
 
-F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
 	F64 min_val = std::numeric_limits<F64>::max();
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -811,14 +797,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, siz
 			: NaN;
 }
 
-F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
 	F64 max_val = std::numeric_limits<F64>::min();
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -834,7 +820,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, siz
 }
 
 // calculates means using aggregates per period
-F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
@@ -842,7 +828,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, si
 	F64 mean = 0;
 	S32 valid_period_count = 0;
 
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -857,7 +843,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, si
 			: NaN;
 }
 
-F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
@@ -866,7 +852,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
 	F64 sum_of_squares = 0;
 	S32 valid_period_count = 0;
 
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -882,14 +868,14 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
 			: NaN;
 }
 
-F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
 	F64 min_val = std::numeric_limits<F64>::max();
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -904,14 +890,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, si
 			: NaN;
 }
 
-F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/)
+F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	bool has_value = false;
 	F64 max_val = std::numeric_limits<F64>::min();
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -927,7 +913,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, siz
 }
 
 
-F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
@@ -935,7 +921,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, s
 	S32 valid_period_count = 0;
 	F64 mean = 0;
 
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -950,13 +936,13 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, s
 			: NaN;
 }
 
-F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	std::vector<F64> buf;
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.getDuration() > (F32Seconds)0.f)
@@ -976,7 +962,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat,
 	return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
 }
 
-F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
@@ -985,7 +971,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
 	S32 valid_period_count = 0;
 	F64 sum_of_squares = 0;
 
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
@@ -1002,13 +988,13 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
 }
 
 
-F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes min_val(std::numeric_limits<F64>::max());
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		min_val = llmin(min_val, recording.getMin(stat));
@@ -1022,13 +1008,13 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, size_t n
 	return getPeriodMin(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
 }
 
-F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/)
+F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes max_val(0.0);
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		max_val = llmax(max_val, recording.getMax(stat));
@@ -1042,14 +1028,14 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, size_t n
 	return getPeriodMax(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
 }
 
-F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 	F64Kilobytes mean(0);
 
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		mean += recording.getMean(stat);
@@ -1063,7 +1049,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, size_t
 	return getPeriodMean(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
 }
 
-F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
+F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 	num_periods = llmin(num_periods, getNumRecordedPeriods());
@@ -1072,7 +1058,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAc
 	S32 valid_period_count = 0;
 	F64 sum_of_squares = 0;
 
-	for (S32 i = 1; i <= num_periods; i++)
+	for (size_t i = 1; i <= num_periods; i++)
 	{
 		Recording& recording = getPrevRecording(i);
 		if (recording.hasValue(stat))
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 8b56721f42f1ef7f219642bd319d993e100c4dcf..a6b1a67d021a1b6a6d5eb32252a667cd492d61c5 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -33,6 +33,7 @@
 #include "lltimer.h"
 #include "lltraceaccumulators.h"
 #include "llpointer.h"
+#include <limits>
 
 class LLStopWatchControlsMixinCommon
 {
@@ -330,7 +331,7 @@ namespace LLTrace
 	:	public LLStopWatchControlsMixin<PeriodicRecording>
 	{
 	public:
-		PeriodicRecording(S32 num_periods, EPlayState state = STOPPED);
+		PeriodicRecording(size_t num_periods, EPlayState state = STOPPED);
 		~PeriodicRecording();
 
 		void nextPeriod();
@@ -353,7 +354,7 @@ namespace LLTrace
 		Recording snapshotCurRecording() const;
 
 		template <typename T>
-		auto getSampleCount(const StatType<T>& stat, size_t num_periods = S32_MAX)
+		auto getSampleCount(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
 			LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
@@ -373,14 +374,14 @@ namespace LLTrace
 
 		// catch all for stats that have a defined sum
 		template <typename T>
-		typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = S32_MAX)
+		typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
 			typename T::value_t min_val(std::numeric_limits<typename T::value_t>::max());
-			for (S32 i = 1; i <= num_periods; i++)
+			for (size_t i = 1; i <= num_periods; i++)
 			{
 				Recording& recording = getPrevRecording(i);
 				if (recording.hasValue(stat))
@@ -396,39 +397,39 @@ namespace LLTrace
 		}
 
 		template<typename T>
-		T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
-		F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T>
-		T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
-		F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T>
-		T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
-		F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
-		F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = S32_MAX);
+		F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
+		F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 
 		template <typename T>
-		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
-			for (S32 i = 1; i <= num_periods; i++)
+			for (size_t i = 1; i <= num_periods; i++)
 			{
 				Recording& recording = getPrevRecording(i);
 				min_val = llmin(min_val, recording.getPerSec(stat));
@@ -437,7 +438,7 @@ namespace LLTrace
 		}
 
 		template<typename T>
-		typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
@@ -449,14 +450,14 @@ namespace LLTrace
 
 		// catch all for stats that have a defined sum
 		template <typename T>
-		typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = S32_MAX)
+		typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			bool has_value = false;
 			typename T::value_t max_val(std::numeric_limits<typename T::value_t>::min());
-			for (S32 i = 1; i <= num_periods; i++)
+			for (size_t i = 1; i <= num_periods; i++)
 			{
 				Recording& recording = getPrevRecording(i);
 				if (recording.hasValue(stat))
@@ -472,39 +473,39 @@ namespace LLTrace
 		}
 
 		template<typename T>
-		T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
-		F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T>
-		T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
-		F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T>
-		T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
-		F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
-		F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = S32_MAX);
+		F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
+		F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 
 		template <typename T>
-		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			F64 max_val = std::numeric_limits<F64>::min();
-			for (S32 i = 1; i <= num_periods; i++)
+			for (size_t i = 1; i <= num_periods; i++)
 			{
 				Recording& recording = getPrevRecording(i);
 				max_val = llmax(max_val, recording.getPerSec(stat));
@@ -513,7 +514,7 @@ namespace LLTrace
 		}
 
 		template<typename T>
-		typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
@@ -525,14 +526,14 @@ namespace LLTrace
 
 		// catch all for stats that have a defined sum
 		template <typename T>
-		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
 
-			for (S32 i = 1; i <= num_periods; i++)
+			for (size_t i = 1; i <= num_periods; i++)
 			{
 				Recording& recording = getPrevRecording(i);
 				if (recording.getDuration() > (F32Seconds)0.f)
@@ -546,39 +547,39 @@ namespace LLTrace
 		}
 
 		template<typename T>
-		typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
-		F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T> 
-		typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
-		F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T>
-		typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
-		F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
-		F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = S32_MAX);
+		F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
+		F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		
 		template <typename T>
-		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			num_periods = llmin(num_periods, getNumRecordedPeriods());
 
 			typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
 
-			for (S32 i = 1; i <= num_periods; i++)
+			for (size_t i = 1; i <= num_periods; i++)
 			{
 				Recording& recording = getPrevRecording(i);
 				if (recording.getDuration() > (F32Seconds)0.f)
@@ -593,64 +594,64 @@ namespace LLTrace
 		}
 
 		template<typename T>
-		typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
 		}
 
-        F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 
-        template <typename T>
-        typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
-        {
-            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
-            num_periods = llmin(num_periods, getNumRecordedPeriods());
-
-            std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
-            for (S32 i = 1; i <= num_periods; i++)
-            {
-                Recording& recording = getPrevRecording(i);
-                if (recording.getDuration() > (F32Seconds)0.f)
-                {
-                    buf.push_back(recording.getPerSec(stat));
-                }
-            }
-            std::sort(buf.begin(), buf.end());
-
-            return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
-        }
-
-        template<typename T>
-        typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
-        {
-            LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
-            return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
-        }
+		template <typename T>
+		typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
+		{
+			LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+			num_periods = llmin(num_periods, getNumRecordedPeriods());
+
+			std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
+			for (size_t i = 1; i <= num_periods; i++)
+			{
+				Recording& recording = getPrevRecording(i);
+				if (recording.getDuration() > (F32Seconds)0.f)
+				{
+					buf.push_back(recording.getPerSec(stat));
+				}
+			}
+			std::sort(buf.begin(), buf.end());
+
+			return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
+		}
+
+		template<typename T>
+		typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
+		{
+			LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
+			return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
+		}
 
 		//
 		// PERIODIC STANDARD DEVIATION
 		//
 
-		F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 
 		template<typename T> 
-		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
 		}
 
-		F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
+		F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 		template<typename T>
-		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
+		typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
 		{
             LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
 			return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
 		}
 
-		F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
-		F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = S32_MAX);
+		F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
+		F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
 
 	private:
 		// implementation for LLStopWatchControlsMixin
@@ -659,6 +660,35 @@ namespace LLTrace
 		/*virtual*/ void handleReset();
 		/*virtual*/ void handleSplitTo(PeriodicRecording& other);
 
+		// helper methods for wraparound ring-buffer arithmetic
+		inline
+		size_t wrapi(size_t i) const
+		{
+			return i % mRecordingPeriods.size();
+		}
+
+		inline
+		size_t nexti(size_t i, size_t offset=1) const
+		{
+			return wrapi(i + offset);
+		}
+
+		inline
+		size_t previ(size_t i, size_t offset=1) const
+		{
+			auto num_periods = mRecordingPeriods.size();
+			// constrain offset
+			offset = llclamp(offset, 0, num_periods - 1);
+			// add size() so expression can't go (unsigned) "negative"
+			return wrapi(i + num_periods - offset);
+		}
+
+		inline
+		void inci(size_t& i, size_t offset=1) const
+		{
+			i = nexti(i, offset);
+		}
+
 	private:
 		std::vector<Recording>	mRecordingPeriods;
 		const bool				mAutoResize;
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 29e3007affd5eacbfa57bf047c1be0f638f26ba1..618f33cc135d650b8f6ec85823635853b81e22fe 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -276,7 +276,7 @@ namespace tut
 			// why does LLSDSerialize::deserialize() reverse the parse() params??
 			mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes)
 			{
-				return (parser(data, istr, max_bytes) > 0);
+				return parser(data, istr, max_bytes);
 			};
 		}