From 2b1cfaf5a20ef771b899adbe5dbdc778b991eacb Mon Sep 17 00:00:00 2001 From: David Wells Date: Sat, 19 Aug 2017 12:56:34 -0400 Subject: [PATCH] Clean up the Timer CPU time calculations. --- include/deal.II/base/timer.h | 7 +- source/base/timer.cc | 147 ++++++++++++++++++++++++----------- 2 files changed, 106 insertions(+), 48 deletions(-) diff --git a/include/deal.II/base/timer.h b/include/deal.II/base/timer.h index 2861185d18..71c227d31f 100644 --- a/include/deal.II/base/timer.h +++ b/include/deal.II/base/timer.h @@ -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; diff --git a/source/base/timer.cc b/source/base/timer.cc index 72994ee64f..090668cd7d 100644 --- a/source/base/timer.cc +++ b/source/base/timer.cc @@ -13,16 +13,21 @@ // // --------------------------------------------------------------------- -#include #include #include -#include #include -#include +#include +#include +#include + +#include +#include #include #include -#include -#include +#include +#include +#include +#include #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H) # include @@ -37,6 +42,84 @@ DEAL_II_NAMESPACE_OPEN +namespace internal +{ + namespace Timer + { + namespace + { + /** + * Type trait for checking whether or not a type is a std::chrono::duration. + */ + template + struct is_duration : std::false_type {}; + + /** + * Specialization to get the right truth value. + */ + template + struct is_duration> : 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 + T + from_seconds(const double time) + { + static_assert(is_duration::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 + double + to_seconds(const std::chrono::duration 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 + T + get_current_cpu_time() + { + static_assert(is_duration::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(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()); } @@ -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()) + - 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()) + - 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 { -- 2.39.5