Browse Source

Low-footprint timer - qcache as example

Proof-of-concept. Add separate thread which will globally
tick every 1ms and store timestamp.
Try to use it where no high precision necessary, in hot loops.
Alexey N. Vinogradov 5 years ago
parent
commit
01dd762b19
4 changed files with 90 additions and 5 deletions
  1. 2 2
      src/CMakeLists.txt
  2. 59 0
      src/mini_timer.cpp
  3. 25 0
      src/mini_timer.h
  4. 4 3
      src/sphinxqcache.cpp

+ 2 - 2
src/CMakeLists.txt

@@ -20,7 +20,7 @@ set ( LIBSPHINX_SRCS sphinx.cpp sphinxexcerpt.cpp
 		searchdexpr.cpp snippetfunctor.cpp snippetindex.cpp snippetstream.cpp
 		snippetpassage.cpp threadutils.cpp sphinxversion.cpp indexcheck.cpp
 		datareader.cpp indexformat.cpp indexsettings.cpp fileutils.cpp coroutine.cpp
-		threads_detached.cpp hazard_pointer.cpp task_info.cpp )
+		threads_detached.cpp hazard_pointer.cpp task_info.cpp mini_timer.cpp )
 set ( INDEXER_SRCS indexer.cpp )
 set ( INDEXTOOL_SRCS indextool.cpp )
 set ( SEARCHD_SRCS_TESTABLE searchdha.cpp http/http_parser.c searchdhttp.cpp
@@ -48,7 +48,7 @@ set ( UDFEXAMPLE_SRC udfexample.c )
 # So if you add headers to the project and NOT see them in visual studio solution - just list them here!
 file ( GLOB HEADERS "sphinx*.h" lz4.h lz4hc.h http/http_parser.h secondaryindex.h searchnode.h killlist.h
 		attribute.h accumulator.h global_idf.h, optional.h, event.h coroutine.h threadutils.h hazard_pointer.h
-		task_info.h )
+		task_info.h mini_timer.h)
 file ( GLOB SEARCHD_H "searchd*.h" "task*.h"  net_action_accept.h netreceive_api.h netreceive_http.h
 		netreceive_ql.h netstate_api.h networking_daemon.h optional.h query_status.h compressed_mysql.h )
 

+ 59 - 0
src/mini_timer.cpp

@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2020, Manticore Software LTD (http://manticoresearch.com)
+// All rights reserved
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License. You should have
+// received a copy of the GPL license along with this program; if you
+// did not, you can find it at http://www.gnu.org/
+//
+
+#include "mini_timer.h"
+#include "threadutils.h"
+
+class TinyTimer_c
+{
+	std::atomic<int64_t> m_tmTimestamp { sphMicroTimer () };
+	SphThread_t m_tCounterThread;
+
+public:
+	TinyTimer_c()
+	{
+		Threads::Create ( &m_tCounterThread, [this] {
+			while (!sphInterrupted ())
+			{
+				m_tmTimestamp.store ( sphMicroTimer (), std::memory_order_relaxed );
+				sphSleepMsec ( sph::MINI_TIMER_TICK_MS );
+			}
+		}, true, "sphTimer" );
+	}
+
+	int64_t MiniTimer ()
+	{
+		return m_tmTimestamp.load ( std::memory_order_relaxed );
+	}
+
+	bool TimeExceeded ( int64_t tmMicroTimestamp )
+	{
+		return MiniTimer() > tmMicroTimestamp;
+	}
+};
+
+TinyTimer_c& g_TinyTimer()
+{
+	static TinyTimer_c tTimer;
+	return tTimer;
+}
+
+
+/// millisecond precision timestamp, returned in microsecond (to be exchangable with sphMicroTimer)
+int64_t sph::MiniTimer ()
+{
+	return g_TinyTimer().MiniTimer();
+}
+
+/// returns true if provided timestamp is already reached or not
+bool sph::TimeExceeded ( int64_t tmMicroTimestamp )
+{
+	return g_TinyTimer ().TimeExceeded ( tmMicroTimestamp );
+}

+ 25 - 0
src/mini_timer.h

@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2020, Manticore Software LTD (http://manticoresearch.com)
+// All rights reserved
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License. You should have
+// received a copy of the GPL license along with this program; if you
+// did not, you can find it at http://www.gnu.org/
+//
+
+#pragma once
+
+#include <cstdint>
+
+namespace sph
+{
+	/// how often timing thread 'ticks'. Default 1ms, but note that thread quantum might be different depending from OS!
+	static const int MINI_TIMER_TICK_MS = 1;
+
+	/// millisecond precision timestamp, returned in microsecond (to be exchangable with sphMicroTimer)
+	int64_t MiniTimer ();
+
+	/// returns true if provided timestamp is already reached or not
+	bool TimeExceeded ( int64_t tmMicroTimestamp );
+}

+ 4 - 3
src/sphinxqcache.cpp

@@ -12,6 +12,7 @@
 
 #include "sphinx.h"
 #include "sphinxqcache.h"
+#include "mini_timer.h"
 
 //////////////////////////////////////////////////////////////////////////
 // QUERY CACHE
@@ -241,7 +242,7 @@ void QcacheEntry_c::Finish()
 #endif
 
 	m_hWeights.Reset(0);
-	m_iElapsedMsec = (int)( ( sphMicroTimer() - m_tmStarted + 500 )/1000 );
+	m_iElapsedMsec = (int)( ( sph::MiniTimer() - m_tmStarted + 500 )/1000 );
 }
 
 //////////////////////////////////////////////////////////////////////////
@@ -431,7 +432,7 @@ QcacheEntry_c * Qcache_c::Find ( int64_t iIndexId, const CSphQuery & q, const IS
 	
 	ScopedMutex_t dLock (m_tLock);
 
-	int64_t tmMin = sphMicroTimer() - int64_t( m_iTtlS)*1000000;
+	int64_t tmMin = sph::MiniTimer() - int64_t( m_iTtlS)*1000000;
 	int iLenMask = m_hData.GetLength() - 1;
 	int iLoop = m_hData.GetLength();
 	int iRes = -1;
@@ -561,7 +562,7 @@ void Qcache_c::EnforceLimits ( bool bSizeOnly )
 		return;
 
 	// if requested, do a full sweep, and recheck ttl and thresh limits
-	int64_t tmMin = sphMicroTimer() - int64_t( m_iTtlS)*1000000;
+	int64_t tmMin = sph::MiniTimer() - int64_t( m_iTtlS)*1000000;
 	ARRAY_FOREACH ( i, m_hData )
 		if ( IsValidEntry(i) && ( m_hData[i]->m_tmStarted < tmMin || m_hData[i]->m_iElapsedMsec < m_iThreshMs ) )
 			DeleteEntry(i);