From 74973a93594e4150a827459708895577a795036b Mon Sep 17 00:00:00 2001
From: Mike Buland <mbuland@penny-arcade.com>
Date: Mon, 2 Jul 2018 11:34:44 -0700
Subject: Added a threadsafe speedometer class.
---
src/tests/speedometer.cpp | 51 ++++++++++++++++++
src/unstable/speedometer.cpp | 120 +++++++++++++++++++++++++++++++++++++++++++
src/unstable/speedometer.h | 43 ++++++++++++++++
3 files changed, 214 insertions(+)
create mode 100644 src/tests/speedometer.cpp
create mode 100644 src/unstable/speedometer.cpp
create mode 100644 src/unstable/speedometer.h
(limited to 'src')
diff --git a/src/tests/speedometer.cpp b/src/tests/speedometer.cpp
new file mode 100644
index 0000000..4532f59
--- /dev/null
+++ b/src/tests/speedometer.cpp
@@ -0,0 +1,51 @@
+#include <bu/sio.h>
+#include <bu/speedometer.h>
+#include <bu/thread.h>
+
+#include <unistd.h>
+
+class Report : public Bu::Thread
+{
+public:
+ Report() :
+ sKeys( 500, 8 )
+ {
+ }
+
+ ~Report()
+ {
+ }
+
+ Bu::Speedometer sKeys;
+ bool bRunning;
+
+protected:
+ virtual void run()
+ {
+ bRunning = true;
+ while( bRunning )
+ {
+ usleep( 500000 );
+// Bu::println("Speed: %1 - %2 k/s").arg( sKeys.getTotalEvents() ).
+// arg( sKeys.getSpeed() );
+ }
+ }
+};
+
+int main( int argc, char *argv[] )
+{
+ Report r;
+
+ r.start();
+
+ for(;;)
+ {
+ getchar();
+ r.sKeys.addEvent();
+ r.sKeys.debug();
+ }
+
+
+ return 0;
+}
+
diff --git a/src/unstable/speedometer.cpp b/src/unstable/speedometer.cpp
new file mode 100644
index 0000000..75e424e
--- /dev/null
+++ b/src/unstable/speedometer.cpp
@@ -0,0 +1,120 @@
+#include "bu/speedometer.h"
+#include "bu/mutexlocker.h"
+#include "bu/sio.h"
+
+#include <sys/time.h>
+#include <string.h>
+
+Bu::Speedometer::Speedometer( int64_t iBucketMs, int32_t iBucketCount ) :
+ aiBucket( NULL ),
+ iTotal( 0 ),
+ iCapacity( iBucketCount ),
+ iFill( 0 ),
+ iStart( 0 ),
+ iCurrent( 0 ),
+ iBucketMs( iBucketMs ),
+ iStartTime( -1 ),
+ iWindowSizeMs( iBucketMs*iBucketCount ),
+ iLastUpdate( -1 )
+{
+ aiBucket = new uint32_t[iCapacity];
+ memset( aiBucket, 0, sizeof(uint32_t)*iCapacity );
+}
+
+Bu::Speedometer::~Speedometer()
+{
+ delete[] aiBucket;
+ aiBucket = NULL;
+}
+
+void Bu::Speedometer::addEvent()
+{
+ Bu::MutexLocker l( mLock );
+ int64_t iNow = getCurrentTime();
+ _updateBuckets( iNow );
+ if( iStartTime < 0 )
+ {
+ iStartTime = iNow;
+ iFill = 1;
+ aiBucket[iCurrent] = 1;
+ iTotal = 1;
+ }
+ else
+ {
+ aiBucket[iCurrent]++;
+ iTotal++;
+ }
+ iLastUpdate = iNow;
+}
+
+void Bu::Speedometer::debug()
+{
+ Bu::MutexLocker l( mLock );
+ Bu::print("%1 of %2: %3:%4: ").
+ arg( iFill ).arg( iCapacity ).arg( iStart ).arg( iCurrent );
+ for( int j = 0; j < iFill; j++ )
+ {
+ Bu::print("%1 | ").arg( aiBucket[(j+iStart)%iCapacity] );
+ }
+ Bu::println(" total = %1").arg( iTotal );
+}
+
+void Bu::Speedometer::_updateBuckets( int64_t iNow )
+{
+ if( iNow > iLastUpdate+iWindowSizeMs )
+ {
+ iLastUpdate = iStartTime = -1;
+ iFill = 0;
+ iStart = iCurrent = 0;
+ aiBucket[iCurrent] = 0;
+ iTotal = 0;
+ }
+ else
+ {
+ int64_t iSkip = (iNow-(iStartTime+iBucketMs*iFill));
+ if( iSkip < 0 )
+ return;
+ iSkip = (iSkip/iBucketMs) + ((iSkip%iBucketMs)?(1):(0));
+
+ for( int64_t j = 0; j < iSkip; j++ )
+ {
+ iCurrent = (iCurrent+1)%iCapacity;
+ if( iFill < iCapacity )
+ {
+ iFill++;
+ }
+ else
+ {
+ iTotal -= aiBucket[iStart];
+ aiBucket[iStart] = 0;
+ iStart = (iStart+1)%iCapacity;
+ iStartTime += iBucketMs;
+ }
+ }
+ }
+}
+
+double Bu::Speedometer::getSpeed()
+{
+ Bu::MutexLocker l( mLock );
+ _updateBuckets( getCurrentTime() );
+
+ if( iStartTime < 0 )
+ return 0.0;
+
+ return (double)iTotal / (double)(iFill*iBucketMs);
+}
+
+int32_t Bu::Speedometer::getTotalEvents()
+{
+ Bu::MutexLocker l( mLock );
+ return iTotal;
+}
+
+int64_t Bu::Speedometer::getCurrentTime() const
+{
+ struct timeval tv;
+ gettimeofday( &tv, NULL );
+ return tv.tv_sec*1000 + tv.tv_usec/1000;
+}
+
diff --git a/src/unstable/speedometer.h b/src/unstable/speedometer.h
new file mode 100644
index 0000000..84d21ed
--- /dev/null
+++ b/src/unstable/speedometer.h
@@ -0,0 +1,43 @@
+#ifndef BU_SPEEDOMETER_H
+#define BU_SPEEDOMETER_H
+
+#include "bu/mutex.h"
+
+#include <stdint.h>
+
+namespace Bu
+{
+ class Speedometer
+ {
+ public:
+ Speedometer( int64_t iBucketMs, int32_t iBucketCount );
+ virtual ~Speedometer();
+
+ void addEvent();
+ double getSpeed();
+ int32_t getTotalEvents();
+ void debug();
+
+ private:
+ void _updateBuckets( int64_t iNow );
+ /**
+ * Gets the current time in milliseconds.
+ */
+ int64_t getCurrentTime() const;
+
+ private:
+ uint32_t *aiBucket;
+ uint32_t iTotal;
+ int32_t iCapacity;
+ int32_t iFill;
+ int32_t iStart;
+ int32_t iCurrent;
+ int64_t iBucketMs;
+ int64_t iStartTime;
+ int64_t iWindowSizeMs;
+ int64_t iLastUpdate;
+ mutable Bu::Mutex mLock;
+ };
+}
+
+#endif
--
cgit v1.2.3