]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Clean up the Timer CPU time calculations. 4917/head
authorDavid Wells <wellsd2@rpi.edu>
Sat, 19 Aug 2017 16:56:34 +0000 (12:56 -0400)
committerDavid Wells <wellsd2@rpi.edu>
Wed, 23 Aug 2017 02:48:34 +0000 (22:48 -0400)
include/deal.II/base/timer.h
source/base/timer.cc

index 2861185d1882a8f59c6fa65ae2bfeedfcce4df63..71c227d31fab3a94b664bf84baae4e7b05dc83dc 100644 (file)
@@ -203,8 +203,11 @@ public:
   double last_wall_time() const;
 
   /**
-   * Access to the current total CPU time without stopping the timer.
-   * The elapsed time is returned in units of seconds.
+   * Access to the current total CPU time without stopping the timer. The
+   * elapsed time is returned in units of seconds.
+   *
+   * If an MPI communicator is provided to the constructor then this value is
+   * summed over all relevant MPI processes.
    */
   double cpu_time() const;
 
index 72994ee64fdac55b35a5065195f50e56ff7dc6db..090668cd7db7864f267e5b66c0312809952e3fbd 100644 (file)
 //
 // ---------------------------------------------------------------------
 
-#include <deal.II/base/timer.h>
 #include <deal.II/base/exceptions.h>
 #include <deal.II/base/mpi.h>
-#include <deal.II/base/utilities.h>
 #include <deal.II/base/signaling_nan.h>
-#include <sstream>
+#include <deal.II/base/thread_management.h>
+#include <deal.II/base/timer.h>
+#include <deal.II/base/utilities.h>
+
+#include <algorithm>
+#include <chrono>
 #include <iostream>
 #include <iomanip>
-#include <algorithm>
-#include <stddef.h>
+#include <map>
+#include <sstream>
+#include <string>
+#include <type_traits>
 
 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
 #  include <sys/time.h>
 
 DEAL_II_NAMESPACE_OPEN
 
+namespace internal
+{
+  namespace Timer
+  {
+    namespace
+    {
+      /**
+       * Type trait for checking whether or not a type is a std::chrono::duration.
+       */
+      template <typename T>
+      struct is_duration : std::false_type {};
+
+      /**
+       * Specialization to get the right truth value.
+       */
+      template <typename Rep, typename Period>
+      struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
+
+      /**
+       * Convert a double precision number with units of seconds into a
+       * specified duration type T. Only valid when T is a
+       * std::chrono::duration type.
+       */
+      template <typename T>
+      T
+      from_seconds(const double time)
+      {
+        static_assert(is_duration<T>::value,
+                      "The template type should be a duration type.");
+        return T(std::lround(T::period::den*(time/T::period::num)));
+      }
+
+      /**
+       * Convert a given duration into a double precision number with units of
+       * seconds.
+       */
+      template <typename Rep, typename Period>
+      double
+      to_seconds(const std::chrono::duration<Rep, Period> duration)
+      {
+        return Period::num*double(duration.count())/Period::den;
+      }
+
+      /**
+       * Return the amount of CPU time that the current process has used so
+       * far. Unfortunately, this requires platform-specific calls, so this
+       * function returns 0 on platforms that are neither windows nor POSIX.
+       */
+      template <typename T>
+      T
+      get_current_cpu_time()
+      {
+        static_assert(is_duration<T>::value,
+                      "The template type should be a duration type.");
+        double system_cpu_duration = 0.0;
+#ifdef DEAL_II_MSVC
+        FILETIME cpuTime, sysTime, createTime, exitTime;
+        if (GetProcessTimes(GetCurrentProcess(), &createTime,
+                            &exitTime, &sysTime, &cpuTime))
+          {
+            system_cpu_duration = (double)
+                                  (((unsigned long long)cpuTime.dwHighDateTime << 32)
+                                   | cpuTime.dwLowDateTime) / 1e6;
+          }
+        // keep the zero value if GetProcessTimes didn't work
+#elif defined(DEAL_II_HAVE_SYS_RESOURCE_H)
+        rusage usage;
+        getrusage (RUSAGE_SELF, &usage);
+        system_cpu_duration = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
+#else
+#  warning "Unsupported platform. Porting not finished."
+#endif
+        return from_seconds<T>(system_cpu_duration);
+      }
+    }
+  }
+}
+
 Timer::Timer()
   :
   Timer(MPI_COMM_SELF, /*sync_wall_time=*/false)
@@ -80,19 +163,6 @@ namespace
       QueryPerformanceCounter(&time);
       return (double) time.QuadPart / freq.QuadPart;
     }
-
-
-    double cpu_clock()
-    {
-      FILETIME cpuTime, sysTime, createTime, exitTime;
-      if (GetProcessTimes(GetCurrentProcess(),  &createTime,
-                          &exitTime, &sysTime, &cpuTime))
-        {
-          return (double)(((unsigned long long)cpuTime.dwHighDateTime << 32)
-                          | cpuTime.dwLowDateTime) / 1e6;
-        }
-      return 0;
-    }
   }
 }
 
@@ -118,16 +188,15 @@ void Timer::start ()
   gettimeofday(&wall_timer, nullptr);
   current_lap_starting_wall_time = wall_timer.tv_sec + 1.e-6 * wall_timer.tv_usec;
 
-  rusage usage;
-  getrusage (RUSAGE_SELF, &usage);
-  current_lap_starting_cpu_time = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
-
 #elif defined(DEAL_II_MSVC)
   current_lap_starting_wall_time = windows::wall_clock();
-  current_lap_starting_cpu_time = windows::cpu_clock();
 #else
 #  error "Unsupported platform. Porting not finished."
 #endif
+  // TODO once we convert all private time variables to chrono types we will
+  // not need to call to_seconds here
+  current_lap_starting_cpu_time = internal::Timer::to_seconds
+                                  (internal::Timer::get_current_cpu_time<std::chrono::nanoseconds>());
 }
 
 
@@ -141,21 +210,20 @@ double Timer::stop ()
 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
 //TODO: Break this out into a function like the functions in
 //namespace windows above
-      rusage usage;
-      getrusage (RUSAGE_SELF, &usage);
-      const double dtime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
-      last_lap_cpu_time = dtime - current_lap_starting_cpu_time;
-
       struct timeval wall_timer;
       gettimeofday(&wall_timer, nullptr);
       last_lap_time = wall_timer.tv_sec + 1.e-6 * wall_timer.tv_usec
                       - current_lap_starting_wall_time;
 #elif defined(DEAL_II_MSVC)
       last_lap_time = windows::wall_clock() - current_lap_starting_wall_time;
-      last_lap_cpu_time = windows::cpu_clock() - current_lap_starting_cpu_time;
 #else
 #  error "Unsupported platform. Porting not finished."
 #endif
+      // TODO once we convert all private time variables to chrono types we will
+      // not need to call to_seconds here
+      last_lap_cpu_time = internal::Timer::to_seconds
+                          (internal::Timer::get_current_cpu_time<std::chrono::nanoseconds>())
+                          - current_lap_starting_cpu_time;
 
       last_lap_data = Utilities::MPI::min_max_avg (last_lap_time,
                                                    mpi_communicator);
@@ -179,24 +247,11 @@ double Timer::cpu_time() const
 {
   if (running)
     {
-#if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
-      rusage usage;
-      getrusage (RUSAGE_SELF, &usage);
-      const double dtime =  usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
-      const double running_time = dtime - current_lap_starting_cpu_time + accumulated_cpu_time;
-
-      // in case of MPI, need to get the time passed by summing the time over
-      // all processes in the network. works also in case we just want to have
-      // the time of a single thread, since then the communicator is
-      // MPI_COMM_SELF
+      const double running_time = internal::Timer::to_seconds
+                                  (internal::Timer::get_current_cpu_time<std::chrono::nanoseconds>())
+                                  - current_lap_starting_cpu_time
+                                  + accumulated_cpu_time;
       return Utilities::MPI::sum (running_time, mpi_communicator);
-
-#elif defined(DEAL_II_MSVC)
-      const double running_time = windows::cpu_clock() - current_lap_starting_cpu_time + accumulated_cpu_time;
-      return running_time;
-#else
-#  error "Unsupported platform. Porting not finished."
-#endif
     }
   else
     {

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.