[mlpack-git] master: Changes to solve issue #498: Replacing timer implementation (d91cf4a)

gitdub at mlpack.org gitdub at mlpack.org
Mon Mar 14 01:04:47 EDT 2016


Repository : https://github.com/mlpack/mlpack
On branch  : master
Link       : https://github.com/mlpack/mlpack/compare/f77416e9ab5bb5d327805f7cb61bf206431ddfed...c0886a18f63c9335a0c39dcc34c27b8925dcb91b

>---------------------------------------------------------------

commit d91cf4a966faead743c61c1552e3f99289437892
Author: na1taneja2821 <namantaneja821 at gmail.com>
Date:   Mon Mar 14 10:34:47 2016 +0530

    Changes to solve issue #498: Replacing timer implementation


>---------------------------------------------------------------

d91cf4a966faead743c61c1552e3f99289437892
 src/mlpack/core/util/cli.cpp    |   4 +-
 src/mlpack/core/util/timers.cpp | 169 +++++++---------------------------------
 src/mlpack/core/util/timers.hpp |  57 ++++----------
 src/mlpack/tests/cli_test.cpp   |   8 +-
 4 files changed, 48 insertions(+), 190 deletions(-)

diff --git a/src/mlpack/core/util/cli.cpp b/src/mlpack/core/util/cli.cpp
index 451428b..0eaf543 100644
--- a/src/mlpack/core/util/cli.cpp
+++ b/src/mlpack/core/util/cli.cpp
@@ -55,7 +55,7 @@ CLI::CLI(const CLI& other) : desc(other.desc),
 CLI::~CLI()
 {
   // Terminate the program timers.
-  std::map<std::string, timeval>::iterator it;
+  std::map<std::string, std::chrono::microseconds>::iterator it;
   for (it = timer.GetAllTimers().begin(); it != timer.GetAllTimers().end();
        ++it)
   {
@@ -72,7 +72,7 @@ CLI::~CLI()
     Print();
 
     Log::Info << "Program timers:" << std::endl;
-    std::map<std::string, timeval>::iterator it;
+    std::map<std::string, std::chrono::microseconds>::iterator it;
     for (it = timer.GetAllTimers().begin(); it != timer.GetAllTimers().end();
         ++it)
     {
diff --git a/src/mlpack/core/util/timers.cpp b/src/mlpack/core/util/timers.cpp
index 4323cb5..eaf6255 100644
--- a/src/mlpack/core/util/timers.cpp
+++ b/src/mlpack/core/util/timers.cpp
@@ -14,19 +14,11 @@
 
 using namespace mlpack;
 
-// On Windows machines, we need to define timersub.
-#ifdef _WIN32
-inline void timersub(const timeval* tvp, const timeval* uvp, timeval* vvp)
+inline std::chrono::microseconds getTimeDuration(const std::chrono::high_resolution_clock::time_point start,
+                                                  const std::chrono::high_resolution_clock::time_point end)
 {
-  vvp->tv_sec = tvp->tv_sec - uvp->tv_sec;
-  vvp->tv_usec = tvp->tv_usec - uvp->tv_usec;
-  if (vvp->tv_usec < 0)
-  {
-     --vvp->tv_sec;
-     vvp->tv_usec += 1000000;
-  }
+  return std::chrono::duration_cast<std::chrono::microseconds>(end - start);
 }
-#endif
 
 /**
  * Start the given timer.
@@ -47,17 +39,17 @@ void Timer::Stop(const std::string& name)
 /**
  * Get the given timer.
  */
-timeval Timer::Get(const std::string& name)
+std::chrono::microseconds Timer::Get(const std::string& name)
 {
   return CLI::GetSingleton().timer.GetTimer(name);
 }
 
-std::map<std::string, timeval>& Timers::GetAllTimers()
+std::map<std::string, std::chrono::microseconds>& Timers::GetAllTimers()
 {
   return timers;
 }
 
-timeval Timers::GetTimer(const std::string& timerName)
+std::chrono::microseconds Timers::GetTimer(const std::string& timerName)
 {
   return timers[timerName];
 }
@@ -69,15 +61,18 @@ bool Timers::GetState(std::string timerName)
 
 void Timers::PrintTimer(const std::string& timerName)
 {
-  timeval& t = timers[timerName];
-  Log::Info << t.tv_sec << "." << std::setw(6) << std::setfill('0')
-      << t.tv_usec << "s";
+  long long int totalDuration = timers[timerName].count();
+  // Converting microseconds to seconds
+  long long int totalDurationSec = totalDuration / 1e6;
+  long long int totalDurationMicroSec = totalDuration % 1000000;
+  Log::Info << totalDurationSec << "." << std::setw(6) << std::setfill('0')
+      << totalDurationMicroSec << "s";
 
   // Also output convenient day/hr/min/sec.
-  int days = t.tv_sec / 86400; // Integer division rounds down.
-  int hours = (t.tv_sec % 86400) / 3600;
-  int minutes = (t.tv_sec % 3600) / 60;
-  int seconds = (t.tv_sec % 60);
+  int days = totalDurationSec / 86400; // Integer division rounds down.
+  int hours = (totalDurationSec % 86400) / 3600;
+  int minutes = (totalDurationSec % 3600) / 60;
+  int seconds = (totalDurationSec % 60);
   // No output if it didn't even take a minute.
   if (!(days == 0 && hours == 0 && minutes == 0))
   {
@@ -111,7 +106,7 @@ void Timers::PrintTimer(const std::string& timerName)
     {
       if (output)
         Log::Info << ", ";
-      Log::Info << seconds << "." << std::setw(1) << (t.tv_usec / 100000) <<
+      Log::Info << seconds << "." << std::setw(1) << (totalDurationMicroSec / 100000) <<
           "secs";
       output = true;
     }
@@ -122,90 +117,9 @@ void Timers::PrintTimer(const std::string& timerName)
   Log::Info << std::endl;
 }
 
-void Timers::GetTime(timeval* tv)
+std::chrono::high_resolution_clock::time_point Timers::GetTime()
 {
-#if defined(__MACH__) && defined(__APPLE__)
-
-  static mach_timebase_info_data_t info;
-
-  // If this is the first time we've run, get the timebase.
-  // We can use denom == 0 to indicate that sTimebaseInfo is
-  // uninitialised.
-  if (info.denom == 0) {
-    (void) mach_timebase_info(&info);
-  }
-
-  // Hope that the multiplication doesn't overflow.
-  uint64_t nsecs = mach_absolute_time() * info.numer / info.denom;
-  tv->tv_sec = nsecs / 1e9;
-  tv->tv_usec = (nsecs / 1e3) - (tv->tv_sec * 1e6);
-
-#elif defined(_POSIX_VERSION)
-#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
-
-  // Get the right clock_id.
-#if defined(CLOCK_MONOTONIC_PRECISE)
-  static const clockid_t id = CLOCK_MONOTONIC_PRECISE;
-#elif defined(CLOCK_MONOTONIC_RAW)
-  static const clockid_t id = CLOCK_MONOTONIC_RAW;
-#elif defined(CLOCK_MONOTONIC)
-  static const clockid_t id = CLOCK_MONOTONIC;
-#elif defined(CLOCK_REALTIME)
-  static const clockid_t id = CLOCK_REALTIME;
-#else
-  static const clockid_t id = ((clockid_t) - 1);
-#endif // CLOCK
-
-  struct timespec ts;
-
-  // Returns the current value tp for the specified clock_id.
-  if (clock_gettime(id, &ts) != -1 && id != ((clockid_t) - 1))
-  {
-    tv->tv_sec = ts.tv_sec;
-    tv->tv_usec = ts.tv_nsec / 1e3;
-  }
-
-  // Fallback for the clock_gettime function.
-  gettimeofday(tv, NULL);
-
-#endif  // _POSIX_TIMERS
-#elif defined(_WIN32)
-
-  static double frequency = 0.0;
-  static LARGE_INTEGER offset;
-
-  // If this is the first time we've run, get the frequency.
-  // We use frequency == 0.0 to indicate that
-  // QueryPerformanceFrequency is uninitialised.
-  if (frequency == 0.0)
-  {
-    LARGE_INTEGER pF;
-    if (!QueryPerformanceFrequency(&pF))
-    {
-      // Fallback for the QueryPerformanceCounter function.
-      FileTimeToTimeVal(tv);
-    }
-    else
-    {
-      QueryPerformanceCounter(&offset);
-      frequency = (double)pF.QuadPart / 1000000.0;
-    }
-  }
-
-  if (frequency != 0.0)
-  {
-    LARGE_INTEGER pC;
-    // Get the current performance-counter value.
-    QueryPerformanceCounter(&pC);
-
-    pC.QuadPart -= offset.QuadPart;
-    double microseconds = (double)pC.QuadPart / frequency;
-    pC.QuadPart = microseconds;
-    tv->tv_sec = (long)pC.QuadPart / 1000000;
-    tv->tv_usec = (long)(pC.QuadPart % 1000000);
-  }
-
-#endif
+  return std::chrono::high_resolution_clock::now();
 }
 
 void Timers::StartTimer(const std::string& timerName)
@@ -220,44 +134,16 @@ void Timers::StartTimer(const std::string& timerName)
 
   timerState[timerName] = true;
 
-  timeval tmp;
-  tmp.tv_sec = 0;
-  tmp.tv_usec = 0;
+  std::chrono::high_resolution_clock::time_point currTime = GetTime();
 
-  GetTime(&tmp);
-
-  // Check to see if the timer already exists.  If it does, we'll subtract the
-  // old value.
-  if (timers.count(timerName) == 1)
+  // If the timer is added first time
+  if(timers.count(timerName) == 0)
   {
-    timeval tmpDelta;
-
-    timersub(&tmp, &timers[timerName], &tmpDelta);
-
-    tmp = tmpDelta;
+    timers[timerName] = (std::chrono::microseconds)0;  
   }
 
-  timers[timerName] = tmp;
-}
-
-#ifdef _WIN32
-void Timers::FileTimeToTimeVal(timeval* tv)
-{
-  FILETIME ftime;
-  uint64_t ptime = 0;
-  // Acquire the file time.
-  GetSystemTimeAsFileTime(&ftime);
-  // Now convert FILETIME to timeval.
-  ptime |= ftime.dwHighDateTime;
-  ptime = ptime << 32;
-  ptime |= ftime.dwLowDateTime;
-  ptime /= 10;
-  ptime -= DELTA_EPOCH_IN_MICROSECS;
-
-  tv->tv_sec = (long) (ptime / 1000000UL);
-  tv->tv_usec = (long) (ptime % 1000000UL);
+  timerStartTime[timerName] = currTime;
 }
-#endif // _WIN32
 
 void Timers::StopTimer(const std::string& timerName)
 {
@@ -271,11 +157,8 @@ void Timers::StopTimer(const std::string& timerName)
 
   timerState[timerName] = false;
 
-  timeval delta, b, a = timers[timerName];
-
-  GetTime(&b);
+  std::chrono::high_resolution_clock::time_point currTime = GetTime();
 
   // Calculate the delta time.
-  timersub(&b, &a, &delta);
-  timers[timerName] = delta;
+  timers[timerName] += getTimeDuration(timerStartTime[timerName], currTime);
 }
diff --git a/src/mlpack/core/util/timers.hpp b/src/mlpack/core/util/timers.hpp
index fb55e73..2ec4f82 100644
--- a/src/mlpack/core/util/timers.hpp
+++ b/src/mlpack/core/util/timers.hpp
@@ -10,46 +10,17 @@
 
 #include <map>
 #include <string>
+#include <chrono> // chrono library for cross platform timer calculation
 
-#if defined(__unix__) || defined(__unix)
-  #include <time.h>       // clock_gettime()
-  #include <sys/time.h>   // timeval, gettimeofday()
-  #include <unistd.h>     // flags like  _POSIX_VERSION
-#elif defined(__MACH__) && defined(__APPLE__)
-  #include <mach/mach_time.h>   // mach_timebase_info,
-                                // mach_absolute_time()
-
-  // TEMPORARY
-  #include <time.h>       // clock_gettime()
-  #include <sys/time.h>   // timeval, gettimeofday()
-  #include <unistd.h>     // flags like  _POSIX_VERSION
-#elif defined(_WIN32)
-  #ifndef NOMINMAX
-    #define NOMINMAX // Don't define min and max macros.
-  #endif
-  #include <windows.h>  // GetSystemTimeAsFileTime(),
-                        // QueryPerformanceFrequency(),
-                        // QueryPerformanceCounter()
-  #include <winsock.h>  // timeval on windows
-  #undef NOMINMAX
-
-  // uint64_t isn't defined on every windows.
+#if defined(_WIN32)
+ // uint64_t isn't defined on every windows.
   #if !defined(HAVE_UINT64_T)
-    #if SIZEOF_UNSIGNED_LONG == 8
-      typedef unsigned long uint64_t;
-    #else
-      typedef unsigned long long  uint64_t;
-    #endif  // SIZEOF_UNSIGNED_LONG
+   #if SIZEOF_UNSIGNED_LONG == 8
+     typedef unsigned long uint64_t;
+   #else
+     typedef unsigned long long  uint64_t;
+   #endif  // SIZEOF_UNSIGNED_LONG
   #endif  // HAVE_UINT64_T
-
-  //gettimeofday has no equivalent will need to write extra code for that.
-  #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
-    #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
-  #else
-    #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
-  #endif // _MSC_VER, _MSC_EXTENSIONS
-#else
-  #error "unknown OS"
 #endif
 
 namespace mlpack {
@@ -90,7 +61,7 @@ class Timer
    *
    * @param name Name of timer to return value of.
    */
-  static timeval Get(const std::string& name);
+  static std::chrono::microseconds Get(const std::string& name);
 };
 
 class Timers
@@ -102,14 +73,14 @@ class Timers
   /**
    * Returns a copy of all the timers used via this interface.
    */
-  std::map<std::string, timeval>& GetAllTimers();
+  std::map<std::string, std::chrono::microseconds>& GetAllTimers();
 
   /**
    * Returns a copy of the timer specified.
    *
    * @param timerName The name of the timer in question.
    */
-  timeval GetTimer(const std::string& timerName);
+  std::chrono::microseconds GetTimer(const std::string& timerName);
 
   /**
    * Prints the specified timer.  If it took longer than a minute to complete
@@ -146,12 +117,14 @@ class Timers
   
  private:
   //! A map of all the timers that are being tracked.
-  std::map<std::string, timeval> timers;
+  std::map<std::string, std::chrono::microseconds> timers;
   //! A map that contains whether or not each timer is currently running.
   std::map<std::string, bool> timerState;
+  //! A map for the starting values of the timers.
+  std::map<std::string, std::chrono::high_resolution_clock::time_point> timerStartTime;
 
   void FileTimeToTimeVal(timeval* tv);
-  void GetTime(timeval* tv);
+  std::chrono::high_resolution_clock::time_point GetTime();
 };
 
 } // namespace mlpack
diff --git a/src/mlpack/tests/cli_test.cpp b/src/mlpack/tests/cli_test.cpp
index 2a53457..32b2321 100644
--- a/src/mlpack/tests/cli_test.cpp
+++ b/src/mlpack/tests/cli_test.cpp
@@ -7,6 +7,8 @@
 
 #include <iostream>
 #include <sstream>
+#include <chrono>
+
 #ifndef _WIN32
   #include <sys/time.h>
 #endif
@@ -240,7 +242,7 @@ BOOST_AUTO_TEST_CASE(MultiRunTimerTest)
 
   Timer::Stop("test_timer");
 
-  BOOST_REQUIRE_GE(Timer::Get("test_timer").tv_usec, 10000);
+  BOOST_REQUIRE_GE(Timer::Get("test_timer").count(), 10000);
 
   // Restart it.
   Timer::Start("test_timer");
@@ -253,7 +255,7 @@ BOOST_AUTO_TEST_CASE(MultiRunTimerTest)
 
   Timer::Stop("test_timer");
 
-  BOOST_REQUIRE_GE(Timer::Get("test_timer").tv_usec, 20000);
+  BOOST_REQUIRE_GE(Timer::Get("test_timer").count(), 20000);
 
   // Just one more time, for good measure...
   Timer::Start("test_timer");
@@ -266,7 +268,7 @@ BOOST_AUTO_TEST_CASE(MultiRunTimerTest)
 
   Timer::Stop("test_timer");
 
-  BOOST_REQUIRE_GE(Timer::Get("test_timer").tv_usec, 40000);
+  BOOST_REQUIRE_GE(Timer::Get("test_timer").count(), 40000);
 }
 
 BOOST_AUTO_TEST_CASE(TwiceStartTimerTest)




More information about the mlpack-git mailing list