From 0671b48316f41517cd052b26000a413c0e8d4d0f Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nicolas.pope@utu.fi>
Date: Fri, 7 Feb 2020 19:35:49 +0200
Subject: [PATCH] Resolves #309 reduce unwanted timer precision

---
 CMakeLists.txt                              |  2 +-
 applications/vision/src/main.cpp            |  2 ++
 components/common/cpp/include/ftl/timer.hpp | 11 ++++++++
 components/common/cpp/src/timer.cpp         | 31 ++++++++++++++-------
 4 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3c25a477..53dc9b883 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,7 +29,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
 
 include(Findglog)
 
-find_package( OpenCV REQUIRED )
+find_package( OpenCV REQUIRED COMPONENTS core imgproc highgui cudaimgproc calib3d imgcodecs videoio aruco cudaarithm cudastereo cudaoptflow face tracking quality)
 find_package( Threads REQUIRED )
 find_package( URIParser REQUIRED )
 find_package( MsgPack REQUIRED )
diff --git a/applications/vision/src/main.cpp b/applications/vision/src/main.cpp
index fde5bf127..3f8dca5ab 100644
--- a/applications/vision/src/main.cpp
+++ b/applications/vision/src/main.cpp
@@ -55,6 +55,8 @@ static void run(ftl::Configurable *root) {
 	Universe *net = ftl::create<Universe>(root, "net");
 	ftl::ctrl::Master ctrl(root, net);
 
+	ftl::timer::setHighPrecision(true);
+
 	auto paths = root->get<vector<string>>("paths");
 	string file = "";
 	if (paths && (*paths).size() > 0) file = (*paths)[(*paths).size()-1];
diff --git a/components/common/cpp/include/ftl/timer.hpp b/components/common/cpp/include/ftl/timer.hpp
index 378cd3d27..bf378425d 100644
--- a/components/common/cpp/include/ftl/timer.hpp
+++ b/components/common/cpp/include/ftl/timer.hpp
@@ -69,9 +69,20 @@ int64_t get_time();
  */
 void setInterval(int ms);
 
+/**
+ * The highprec parameter sets whether or not this
+ * timer should be high precision on the calling interval. A high precision
+ * timer involves spinning the cpu to achieve millisecond accuracy.
+ */
+void setHighPrecision(bool hp);
+
 int getInterval();
 
+/**
+ * Get current (monotonic) time in milliseconds.
+ */
 int64_t get_time();
+
 int64_t get_time_micro();
 double get_time_seconds();
 
diff --git a/components/common/cpp/src/timer.cpp b/components/common/cpp/src/timer.cpp
index d58386c01..79fb8720b 100644
--- a/components/common/cpp/src/timer.cpp
+++ b/components/common/cpp/src/timer.cpp
@@ -20,6 +20,7 @@ using namespace ftl::timer;
 
 static int64_t last_frame = 0;
 static int64_t mspf = 50;
+static bool hprec_ = false;
 static int64_t clock_adjust = 0;
 static bool active = false;
 static std::atomic<int> active_jobs = 0;
@@ -59,7 +60,7 @@ static void waitTimePoint() {
 	int64_t msdelay = mspf - (now % mspf);
 	int64_t sincelast = now - last_frame*mspf;
 
-	if (sincelast > mspf) LOG(WARNING) << "Frame " << "(" << (target-last_frame) << ") dropped by " << sincelast << "ms";
+	if (hprec_ && sincelast > mspf) LOG(WARNING) << "Frame " << "(" << (target-last_frame) << ") dropped by " << (sincelast-mspf) << "ms";
 
 	// Use sleep_for for larger delays
 	
@@ -89,15 +90,21 @@ static void waitTimePoint() {
 		}
 	}
 
-	// Spin loop until exact grab time
-	//LOG(INFO) << "Spin Delay: " << (now / 40) << " = " << (40 - (now%40));
-
-	if (sincelast != mspf) {
-		target = now / mspf;
-		while ((now/mspf) == target) {
-			_mm_pause();  // SSE2 nano pause intrinsic
-			now = get_time();
-		};
+	if (hprec_) {
+		// Spin loop until exact grab time
+		// Accurate to around 4 micro seconds.
+		if (sincelast != mspf) {
+			// TODO: Try using sleep_for for msdelay-1
+			target = now / mspf;
+			while ((now/mspf) == target) {
+				_mm_pause();  // SSE2 nano pause intrinsic
+				now = get_time();
+			};
+		}
+	} else {
+		// Accurate to just under 1 millisecond usually
+		if (sincelast != mspf) sleep_for(milliseconds(msdelay));
+		now = get_time();
 	}
 	last_frame = now/mspf;
 }
@@ -106,6 +113,10 @@ void ftl::timer::setInterval(int ms) {
 	mspf = ms;
 }
 
+void ftl::timer::setHighPrecision(bool hp) {
+	hprec_ = hp;
+}
+
 int ftl::timer::getInterval() {
 	return mspf;
 }
-- 
GitLab