diff --git a/.travis.yml b/.travis.yml index 27d41af30..9cc89a3f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ addons: apt: packages: - libboost-dev + - libboost-chrono-dev - libboost-date-time-dev - libboost-thread-dev - libjpeg8-dev diff --git a/platform/unix/syspovtimer.cpp b/platform/unix/syspovtimer.cpp deleted file mode 100644 index 3b3018e43..000000000 --- a/platform/unix/syspovtimer.cpp +++ /dev/null @@ -1,307 +0,0 @@ -//****************************************************************************** -/// -/// @file platform/unix/syspovtimer.cpp -/// -/// Unix-specific implementation of the @ref pov_base::Delay() function and -/// @ref pov_base::Timer class. -/// -/// @copyright -/// @parblock -/// -/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. -/// -/// POV-Ray is free software: you can redistribute it and/or modify -/// it under the terms of the GNU Affero General Public License as -/// published by the Free Software Foundation, either version 3 of the -/// License, or (at your option) any later version. -/// -/// POV-Ray is distributed in the hope that it will be useful, -/// but WITHOUT ANY WARRANTY; without even the implied warranty of -/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -/// GNU Affero General Public License for more details. -/// -/// You should have received a copy of the GNU Affero General Public License -/// along with this program. If not, see . -/// -/// ---------------------------------------------------------------------------- -/// -/// POV-Ray is based on the popular DKB raytracer version 2.12. -/// DKBTrace was originally written by David K. Buck. -/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. -/// -/// @endparblock -/// -//****************************************************************************** - -#include "syspovtimer.h" - -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#include "base/types.h" - -// this must be the last file included -#include "base/povdebug.h" - -#if !defined(HAVE_CLOCKID_T) -typedef int clockid_t; -#endif - -#if !defined(HAVE_USECONDS_T) -typedef long useconds_t; -#endif - -namespace pov_base -{ - -//****************************************************************************** - -#if !POV_USE_DEFAULT_DELAY - -void Delay(unsigned int msec) -{ -#if defined(HAVE_NANOSLEEP) - timespec ts; - ts.tv_sec = msec / 1000; - ts.tv_nsec = (POV_ULONG) (1000000) * (msec % 1000); - nanosleep(&ts, NULL); -#elif defined(HAVE_USLEEP) - POV_ASSERT(msec < 1000); // On some systems, usleep() does not support sleeping for 1 second or more. - usleep (msec * (useconds_t)1000); -#else -#error "Bad compile-time configuration." -#endif -} - -#endif // !POV_USE_DEFAULT_DELAY - -//****************************************************************************** - -#if !POV_USE_DEFAULT_TIMER - -/// Attempt to get milliseconds time using `clock_gettime()`. -static inline bool ClockGettimeMillisec(POV_ULONG& result, clockid_t source) -{ -#if defined(HAVE_CLOCK_GETTIME) - struct timespec ts; - bool success = (clock_gettime (source, &ts) == 0); - if (success) - result = static_cast(ts.tv_sec) *1000 - + static_cast(ts.tv_nsec) /1000000; - return success; -#else - return false; -#endif -} - -/// Attempt to get milliseconds elapsed CPU-time using `getrusage()`. -static inline bool GetrusageMillisec(POV_ULONG& result, int source) -{ -#if defined(HAVE_GETRUSAGE) - struct rusage ru; - bool success = (getrusage(source, &ru) == 0); - if (success) - result = (static_cast(ru.ru_utime.tv_sec) + static_cast(ru.ru_stime.tv_sec)) *1000 - + (static_cast(ru.ru_utime.tv_usec) + static_cast(ru.ru_stime.tv_usec)) /1000; - return success; -#else - return false; -#endif -} - -/// Attempt to get milliseconds since the Epoch (1970-01-01) using `gettimeofday()`. -static inline bool GettimeofdayMillisec(POV_ULONG& result) -{ -#if defined(HAVE_GETTIMEOFDAY) - struct timeval tv; // seconds + microseconds since - bool success = (gettimeofday(&tv, NULL) == 0); - if (success) - result = static_cast(tv.tv_sec) *1000 - + static_cast(tv.tv_usec) /1000; - return success; -#else - return false; -#endif -} - -Timer::Timer () : - mWallTimeUseClockGettimeMonotonic (false), - mWallTimeUseClockGettimeRealtime (false), - mWallTimeUseGettimeofday (false), - mProcessTimeUseGetrusageSelf (false), - mProcessTimeUseClockGettimeProcess (false), - mProcessTimeUseFallback (false), - mThreadTimeUseGetrusageThread (false), - mThreadTimeUseGetrusageLwp (false), - mThreadTimeUseClockGettimeThread (false), - mThreadTimeUseFallback (false) -{ - // Figure out which timer source to use for wall clock time. - bool haveWallTime = false; -#if defined(HAVE_DECL_CLOCK_MONOTONIC) && HAVE_DECL_CLOCK_MONOTONIC - if (!haveWallTime) - haveWallTime = mWallTimeUseClockGettimeMonotonic = ClockGettimeMillisec(mWallTimeStart, CLOCK_MONOTONIC); -#endif - // we prefer CLOCK_MONOTONIC over CLOCK_REALTIME because the former will not be affected if someone adjusts the - // system's real-time clock. -#if defined(HAVE_DECL_CLOCK_REALTIME) && HAVE_DECL_CLOCK_REALTIME - if (!haveWallTime) - haveWallTime = mWallTimeUseClockGettimeRealtime = ClockGettimeMillisec(mWallTimeStart, CLOCK_REALTIME); -#endif - // TODO - Find out if there is some rationale behind the preference of clock_gettime() over - // gettimeofday(), and document it here. - if (!haveWallTime) - haveWallTime = mWallTimeUseGettimeofday = GettimeofdayMillisec(mWallTimeStart); - // FIXME: add fallback, using ftime(), or time() + a counter for ms, or maybe boost::date_time - if (!haveWallTime) - { - POV_ASSERT(false); - mWallTimeStart = 0; - } - - // Figure out which timer source to use for per-process CPU time. - bool haveProcessTime = false; -#if defined(HAVE_DECL_RUSAGE_SELF) && HAVE_DECL_RUSAGE_SELF - if (!haveProcessTime) - haveProcessTime = mProcessTimeUseGetrusageSelf = GetrusageMillisec(mProcessTimeStart, RUSAGE_SELF); -#endif - // We prefer getrusage() over clock_gettime() because the latter may be inaccurate on systems - // with multiple physical processors. -#if defined(HAVE_DECL_CLOCK_PROCESS_CPUTIME_ID) && HAVE_DECL_CLOCK_PROCESS_CPUTIME_ID - if (!haveProcessTime) - haveProcessTime = mProcessTimeUseClockGettimeProcess = ClockGettimeMillisec(mProcessTimeStart, CLOCK_PROCESS_CPUTIME_ID); -#endif - if (!haveProcessTime) - { - haveProcessTime = mProcessTimeUseFallback = haveWallTime; - mProcessTimeStart = mWallTimeStart; - } - - // Figure out which timer source to use for per-thread CPU time. - bool haveThreadTime = false; -#if defined(HAVE_DECL_RUSAGE_THREAD) && HAVE_DECL_RUSAGE_THREAD - if (!haveThreadTime) - haveThreadTime = mThreadTimeUseGetrusageThread = GetrusageMillisec(mThreadTimeStart, RUSAGE_THREAD); -#elif defined(HAVE_DECL_RUSAGE_LWP) && HAVE_DECL_RUSAGE_LWP // should be alias of RUSAGE_THREAD on systems that support both - if (!haveThreadTime) - haveThreadTime = mThreadTimeUseGetrusageLwp = GetrusageMillisec(mThreadTimeStart, RUSAGE_LWP); -#endif - // We prefer getrusage() over clock_gettime() because the latter may be inaccurate on systems - // with multiple physical processors. -#if defined(HAVE_DECL_CLOCK_THREAD_CPUTIME_ID) && HAVE_DECL_CLOCK_THREAD_CPUTIME_ID - if (!haveThreadTime) - haveThreadTime = mThreadTimeUseClockGettimeThread = ClockGettimeMillisec(mThreadTimeStart, CLOCK_THREAD_CPUTIME_ID); -#endif - if (!haveThreadTime) - { - haveThreadTime = mThreadTimeUseFallback = haveProcessTime; - mThreadTimeStart = mProcessTimeStart; - } -} - -Timer::~Timer () -{ - // nothing to do -} - -POV_ULONG Timer::GetWallTime () const -{ - POV_ULONG result; -#if defined(HAVE_DECL_CLOCK_MONOTONIC) && HAVE_DECL_CLOCK_MONOTONIC - if (mWallTimeUseClockGettimeMonotonic) - return (ClockGettimeMillisec(result, CLOCK_MONOTONIC) ? result : 0); -#endif -#if defined(HAVE_DECL_CLOCK_REALTIME) && HAVE_DECL_CLOCK_REALTIME - if (mWallTimeUseClockGettimeRealtime) - return (ClockGettimeMillisec(result, CLOCK_REALTIME) ? result : 0); -#endif - if (mWallTimeUseGettimeofday) - return (GettimeofdayMillisec(result) ? result : 0); - return 0; -} - -POV_ULONG Timer::GetProcessTime () const -{ - POV_ULONG result; -#if defined(HAVE_DECL_RUSAGE_SELF) && HAVE_DECL_RUSAGE_SELF - if (mProcessTimeUseGetrusageSelf) - return (GetrusageMillisec(result, RUSAGE_SELF) ? result : 0); -#endif -#if defined(HAVE_DECL_CLOCK_PROCESS_CPUTIME_ID) && HAVE_DECL_CLOCK_PROCESS_CPUTIME_ID - if (mProcessTimeUseClockGettimeProcess) - return (ClockGettimeMillisec(result, CLOCK_PROCESS_CPUTIME_ID) ? result : 0); -#endif - if (mProcessTimeUseFallback) - return GetWallTime (); - return 0; -} - -POV_ULONG Timer::GetThreadTime () const -{ - POV_ULONG result; -#if defined(HAVE_DECL_RUSAGE_THREAD) && HAVE_DECL_RUSAGE_THREAD - if (mThreadTimeUseGetrusageThread) - return (GetrusageMillisec(result, RUSAGE_THREAD) ? result : 0); -#endif -#if defined(HAVE_DECL_RUSAGE_LWP) && HAVE_DECL_RUSAGE_LWP - if (mThreadTimeUseGetrusageLwp) - return (GetrusageMillisec(result, RUSAGE_LWP) ? result : 0); -#endif -#if defined(HAVE_DECL_CLOCK_THREAD_CPUTIME_ID) && HAVE_DECL_CLOCK_THREAD_CPUTIME_ID - if (mThreadTimeUseClockGettimeThread) - return (ClockGettimeMillisec(result, CLOCK_THREAD_CPUTIME_ID) ? result : 0); -#endif - if (mThreadTimeUseFallback) - return GetProcessTime (); - return 0; -} - -POV_LONG Timer::ElapsedRealTime () const -{ - return GetWallTime () - mWallTimeStart; -} - -POV_LONG Timer::ElapsedProcessCPUTime () const -{ - return GetProcessTime () - mProcessTimeStart; -} - -POV_LONG Timer::ElapsedThreadCPUTime () const -{ - return GetThreadTime () - mThreadTimeStart; -} - -void Timer::Reset () -{ - mWallTimeStart = GetWallTime (); - mProcessTimeStart = GetProcessTime (); - mThreadTimeStart = GetThreadTime (); -} - -bool Timer::HasValidProcessCPUTime () const -{ - return !mProcessTimeUseFallback; -} - -bool Timer::HasValidThreadCPUTime () const -{ - return !mThreadTimeUseFallback; -} - -#endif // !POV_USE_DEFAULT_TIMER - -//****************************************************************************** - -} diff --git a/platform/unix/syspovtimer.h b/platform/unix/syspovtimer.h deleted file mode 100644 index 64bb75367..000000000 --- a/platform/unix/syspovtimer.h +++ /dev/null @@ -1,109 +0,0 @@ -//****************************************************************************** -/// -/// @file platform/unix/syspovtimer.h -/// -/// Unix-specific declaration of the @ref pov_base::Delay() function and -/// @ref pov_base::Timer class. -/// -/// @copyright -/// @parblock -/// -/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. -/// -/// POV-Ray is free software: you can redistribute it and/or modify -/// it under the terms of the GNU Affero General Public License as -/// published by the Free Software Foundation, either version 3 of the -/// License, or (at your option) any later version. -/// -/// POV-Ray is distributed in the hope that it will be useful, -/// but WITHOUT ANY WARRANTY; without even the implied warranty of -/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -/// GNU Affero General Public License for more details. -/// -/// You should have received a copy of the GNU Affero General Public License -/// along with this program. If not, see . -/// -/// ---------------------------------------------------------------------------- -/// -/// POV-Ray is based on the popular DKB raytracer version 2.12. -/// DKBTrace was originally written by David K. Buck. -/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. -/// -/// @endparblock -/// -//****************************************************************************** - -#ifndef POVRAY_UNIX_SYSPOVTIMER_H -#define POVRAY_UNIX_SYSPOVTIMER_H - -#include "base/configbase.h" - -namespace pov_base -{ - -#if !POV_USE_DEFAULT_DELAY - -void Delay(unsigned int msec); - -#endif // !POV_USE_DEFAULT_DELAY - - -#if !POV_USE_DEFAULT_TIMER - -/// Millisecond-precision timer. -/// -/// This is the Unix-specific implementation of the millisecond-precision timer required by POV-Ray. -/// -/// @impl -/// Note that to measure per-process CPU time we're not using `clock()` as a fallback -/// implementation, as depending on the platform it may incorrectly report elapsed wall-clock -/// time (sources on the internet report this for Solaris), and/or may be limited to timespans -/// in the order of an hour (any system with a 32-bit `clock_t` and a standard `CLOCKS_PER_SEC` -/// of 1,000,000). -/// -class Timer -{ - public: - - Timer(); - ~Timer(); - - POV_LONG ElapsedRealTime() const; - POV_LONG ElapsedProcessCPUTime() const; - POV_LONG ElapsedThreadCPUTime() const; - - void Reset(); - - bool HasValidProcessCPUTime() const; - bool HasValidThreadCPUTime() const; - - private: - - POV_ULONG mWallTimeStart; - POV_ULONG mProcessTimeStart; - POV_ULONG mThreadTimeStart; - - bool mWallTimeUseClockGettimeMonotonic : 1; ///< Whether we'll measure elapsed wall-clock time using `clock_gettime(CLOCK_MONOTONIC)`. - bool mWallTimeUseClockGettimeRealtime : 1; ///< Whether we'll measure elapsed wall-clock time using `clock_gettime(CLOCK_REALTIME)`. - bool mWallTimeUseGettimeofday : 1; ///< Whether we'll measure elapsed wall-clock time using `gettimeofday()`. - - bool mProcessTimeUseGetrusageSelf : 1; ///< Whether we'll measure per-process CPU time using `getrusage(RUSAGE_SELF)`. - bool mProcessTimeUseClockGettimeProcess : 1; ///< Whether we'll measure per-process CPU time using `clock_gettime(CLOCK_PROCESS_CPUTIME_ID)`. - bool mProcessTimeUseFallback : 1; ///< Whether we'll fall back to wall-clock time instead of per-process CPU time. - - bool mThreadTimeUseGetrusageThread : 1; ///< Whether we'll measure per-thread CPU time using `getrusage(RUSAGE_THREAD)`. - bool mThreadTimeUseGetrusageLwp : 1; ///< Whether we'll measure per-thread CPU time using `getrusage(RUSAGE_LWP)`. - bool mThreadTimeUseClockGettimeThread : 1; ///< Whether we'll measure per-thread CPU time `clock_gettime(CLOCK_THREAD_CPUTIME_ID)`. - bool mThreadTimeUseFallback : 1; ///< Whether we'll fall back to per-process CPU time (or wall-clock time) instead of per-thread CPU time. - - POV_ULONG GetWallTime() const; - POV_ULONG GetThreadTime() const; - POV_ULONG GetProcessTime() const; -}; - -#endif // !POV_USE_DEFAULT_TIMER - -} - -#endif // POVRAY_UNIX_SYSPOVTIMER_H diff --git a/platform/windows/syspovtimer.cpp b/platform/windows/syspovtimer.cpp deleted file mode 100644 index ef8684afc..000000000 --- a/platform/windows/syspovtimer.cpp +++ /dev/null @@ -1,179 +0,0 @@ -//****************************************************************************** -/// -/// @file platform/windows/syspovtimer.cpp -/// -/// Windows-specific implementation of the @ref pov_base::Delay() function and -/// @ref pov_base::Timer class. -/// -/// @copyright -/// @parblock -/// -/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. -/// -/// POV-Ray is free software: you can redistribute it and/or modify -/// it under the terms of the GNU Affero General Public License as -/// published by the Free Software Foundation, either version 3 of the -/// License, or (at your option) any later version. -/// -/// POV-Ray is distributed in the hope that it will be useful, -/// but WITHOUT ANY WARRANTY; without even the implied warranty of -/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -/// GNU Affero General Public License for more details. -/// -/// You should have received a copy of the GNU Affero General Public License -/// along with this program. If not, see . -/// -/// ---------------------------------------------------------------------------- -/// -/// POV-Ray is based on the popular DKB raytracer version 2.12. -/// DKBTrace was originally written by David K. Buck. -/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. -/// -/// @endparblock -/// -//****************************************************************************** - -#include "syspovtimer.h" - -#include - -#include -#include -#include - -#include "base/types.h" - -#include "osversioninfo.h" - -// this must be the last file included -#include "base/povdebug.h" - -namespace pov_base -{ - -//****************************************************************************** - -void Delay(unsigned int msec) -{ - Sleep (msec); -} - -//****************************************************************************** - -Timer::Timer () : - // TODO - sources on the internet indicate that GetThreadTimes() and GetProcessTimes() have been - // around as early as NT 3.1. Is there a reason we're only making use of it in NT 4.0 and - // later Windows versions? - mThreadHandle (NULL), - mCPUTimeSupported (WindowsVersionDetector().IsNTVersion (4,0)) -{ - if (mCPUTimeSupported) - { - if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), - &mThreadHandle, 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - POV_ASSERT (false); - mThreadHandle = NULL; - } - } - Reset (); -} - -Timer::~Timer () -{ - if (mThreadHandle != NULL) - CloseHandle (mThreadHandle); -} - -POV_ULONG Timer::GetWallTime () const -{ - struct timeb tb; - ftime(&tb); - return (static_cast(tb.time) * 1000 + tb.millitm); -} - -POV_ULONG Timer::GetThreadTime () const -{ - FILETIME ct; - FILETIME et; - __int64 kt; - __int64 ut; - BOOL success; - - POV_ASSERT (mCPUTimeSupported); - - success = GetThreadTimes (mThreadHandle, &ct, &et, - reinterpret_cast(&kt), - reinterpret_cast(&ut)); - - POV_ASSERT (success); - if (!success) - return 0; - - return ((kt + ut) / 10000); -} - -POV_ULONG Timer::GetProcessTime () const -{ - FILETIME ct; - FILETIME et; - __int64 kt; - __int64 ut; - BOOL success; - - POV_ASSERT (mCPUTimeSupported); - - success = GetProcessTimes (GetCurrentProcess (), &ct, &et, - reinterpret_cast(&kt), - reinterpret_cast(&ut)); - - POV_ASSERT (success); - if (!success) - return 0; - - return ((kt + ut) / 10000); -} - -POV_LONG Timer::ElapsedRealTime () const -{ - return GetWallTime () - mWallTimeStart; -} - -POV_LONG Timer::ElapsedThreadCPUTime () const -{ - if (mCPUTimeSupported) - return GetThreadTime () - mThreadTimeStart; - else - return GetWallTime () - mWallTimeStart; -} - -POV_LONG Timer::ElapsedProcessCPUTime () const -{ - if (mCPUTimeSupported) - return GetProcessTime () - mProcessTimeStart; - else - return GetWallTime () - mWallTimeStart; -} - -void Timer::Reset () -{ - mWallTimeStart = GetWallTime (); - if (mCPUTimeSupported) - { - mThreadTimeStart = GetThreadTime (); - mProcessTimeStart = GetProcessTime (); - } -} - -bool Timer::HasValidThreadCPUTime () const -{ - return mCPUTimeSupported; -} - -bool Timer::HasValidProcessCPUTime () const -{ - return mCPUTimeSupported; -} - -} diff --git a/platform/windows/syspovtimer.h b/platform/windows/syspovtimer.h deleted file mode 100644 index 9405ceacd..000000000 --- a/platform/windows/syspovtimer.h +++ /dev/null @@ -1,77 +0,0 @@ -//****************************************************************************** -/// -/// @file platform/windows/syspovtimer.h -/// -/// Windows-specific declaration of the @ref pov_base::Delay() function and -/// @ref pov_base::Timer class. -/// -/// @copyright -/// @parblock -/// -/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. -/// -/// POV-Ray is free software: you can redistribute it and/or modify -/// it under the terms of the GNU Affero General Public License as -/// published by the Free Software Foundation, either version 3 of the -/// License, or (at your option) any later version. -/// -/// POV-Ray is distributed in the hope that it will be useful, -/// but WITHOUT ANY WARRANTY; without even the implied warranty of -/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -/// GNU Affero General Public License for more details. -/// -/// You should have received a copy of the GNU Affero General Public License -/// along with this program. If not, see . -/// -/// ---------------------------------------------------------------------------- -/// -/// POV-Ray is based on the popular DKB raytracer version 2.12. -/// DKBTrace was originally written by David K. Buck. -/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. -/// -/// @endparblock -/// -//****************************************************************************** - -#ifndef POVRAY_WINDOWS_SYSPOVTIMER_H -#define POVRAY_WINDOWS_SYSPOVTIMER_H - -#include "base/configbase.h" - -namespace pov_base -{ - -void Delay(unsigned int msec); - -class Timer -{ - public: - Timer(); - ~Timer(); - - POV_LONG ElapsedRealTime() const; - POV_LONG ElapsedThreadCPUTime() const; - POV_LONG ElapsedProcessCPUTime() const; - - void Reset(); - - bool HasValidThreadCPUTime() const; - bool HasValidProcessCPUTime() const; - - private: - - POV_ULONG mWallTimeStart; - POV_ULONG mThreadTimeStart; - POV_ULONG mProcessTimeStart; - void* mThreadHandle; - bool mCPUTimeSupported : 1; - - POV_ULONG GetWallTime () const; - POV_ULONG GetThreadTime () const; - POV_ULONG GetProcessTime () const; -}; - -} - -#endif // POVRAY_WINDOWS_SYSPOVTIMER_H diff --git a/source/base/timer.cpp b/source/base/timer.cpp index fd7672434..3ee4c74cb 100644 --- a/source/base/timer.cpp +++ b/source/base/timer.cpp @@ -2,13 +2,14 @@ /// /// @file base/timer.cpp /// -/// @todo What's in here? +/// Contains implementations of the @ref pov_base::Delay() function and the +/// @ref pov_base::Timer class. /// /// @copyright /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -54,12 +55,7 @@ namespace pov_base void Delay(unsigned int msec) { - boost::xtime t; - boost::xtime_get(&t, POV_TIME_UTC); - POV_ULONG ns = (POV_ULONG)(t.sec) * (POV_ULONG)(1000000000) + (POV_ULONG)(t.nsec) + (POV_ULONG)(msec) * (POV_ULONG)(1000000); - t.sec = (boost::xtime::xtime_sec_t)(ns / (POV_ULONG)(1000000000)); - t.nsec = (boost::xtime::xtime_nsec_t)(ns % (POV_ULONG)(1000000000)); - boost::thread::sleep(t); + boost::this_thread::sleep_for(boost::chrono::milliseconds(msec)); } #endif // POV_MULTITHREADED && POV_USE_DEFAULT_DELAY @@ -77,16 +73,69 @@ Timer::~Timer() POV_LONG Timer::ElapsedRealTime() const { - boost::xtime t; - boost::xtime_get(&t, POV_TIME_UTC); - POV_LONG tt = (POV_LONG)(t.sec) * (POV_LONG)(1000000000) + (POV_LONG)(t.nsec); - POV_LONG st = (POV_LONG)(mRealTimeStart.sec) * (POV_LONG)(1000000000) + (POV_LONG)(mRealTimeStart.nsec); - return ((tt - st) / (POV_LONG)(1000000)); +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + return static_cast(boost::chrono::duration_cast + (boost::chrono::steady_clock::now() - mRealTimeStart).count()); +#else + return static_cast(boost::chrono::duration_cast + (boost::chrono::system_clock::now() - mRealTimeStart).count()); +#endif +} + +POV_LONG Timer::ElapsedProcessCPUTime() const +{ +#ifdef BOOST_CHRONO_HAS_PROCESS_CLOCKS + return static_cast(boost::chrono::duration_cast + (boost::chrono::process_real_cpu_clock::now() - mProcessTimeStart).count()); +#else + return ElapsedRealTime(); +#endif +} + +POV_LONG Timer::ElapsedThreadCPUTime() const +{ +#ifdef BOOST_CHRONO_HAS_THREAD_CLOCK + return static_cast(boost::chrono::duration_cast + (boost::chrono::thread_clock::now() - mThreadTimeStart).count()); +#else + return ElapsedProcessCPUTime(); +#endif +} + + +bool Timer::HasValidProcessCPUTime() const +{ +#ifdef BOOST_CHRONO_HAS_PROCESS_CLOCKS + return true; +#else + return false; +#endif +} + +bool Timer::HasValidThreadCPUTime() const +{ +#ifdef BOOST_CHRONO_HAS_THREAD_CLOCK + return true; +#else + return false; +#endif } void Timer::Reset() { - boost::xtime_get(&mRealTimeStart, POV_TIME_UTC); +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + mRealTimeStart = boost::chrono::steady_clock::now(); +#else + mRealTimeStart = boost::chrono::system_clock::now(); +#endif + +#ifdef BOOST_CHRONO_HAS_PROCESS_CLOCKS + mProcessTimeStart = boost::chrono::process_real_cpu_clock::now(); +#endif + +#ifdef BOOST_CHRONO_HAS_THREAD_CLOCK + mThreadTimeStart = boost::chrono::thread_clock::now(); +#endif } #endif // POV_USE_DEFAULT_TIMER diff --git a/source/base/timer.h b/source/base/timer.h index e600425f5..894251bef 100644 --- a/source/base/timer.h +++ b/source/base/timer.h @@ -2,13 +2,14 @@ /// /// @file base/timer.h /// -/// @todo What's in here? +/// Contains declarations of the @ref pov_base::Delay() function and the +/// @ref pov_base::Timer class. /// /// @copyright /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -39,8 +40,10 @@ // Module config header file must be the first file included within POV-Ray unit header files #include "base/configbase.h" -#if POV_USE_DEFAULT_TIMER -#include +#if POV_USE_DEFAULT_TIMER || (POV_MULTITHREADED && POV_USE_DEFAULT_DELAY) +#include +#include +#include #endif #if !POV_USE_DEFAULT_TIMER || (POV_MULTITHREADED && !POV_USE_DEFAULT_DELAY) @@ -64,12 +67,8 @@ namespace pov_base /// This function puts the current thread into idle mode for the specified time. /// /// @note -/// This is a default implementation, provided only as a last-ditch resort for platforms that -/// cannot provide a better implementation. -/// -/// @todo -/// The current implementation is based on boost::xtime, which has been deprecated since -/// boost 1.34. +/// This is a general implementation based on boost::thread + boost::chrono. It should probably +/// be fine for most platforms. /// /// @attention /// Due to possible limitations of platform-specific implementations, this function may only be @@ -91,19 +90,8 @@ void Delay(unsigned int msec); /// Millisecond-precision timer. /// /// @note -/// This is a default implementation, provided only as a last-ditch resort for platforms that -/// cannot provide a better implementation. It can neither guarantee millisecond precision, nor -/// does it support measurement of CPU time. -/// -/// @todo -/// This implementation is based on boost::xtime, which has been deprecated since 1.34. -/// -/// @impl -/// Note that to measure per-process CPU time we're not resorting to `clock()` as a default -/// implementation, as depending on the platform it may incorrectly report elapsed wall-clock -/// time (sources on the internet report this for Solaris, and it is a well-documented fact for -/// Windows), and/or may be limited to timespans in the order of an hour (any system with a -/// 32-bit `clock_t` and a standard `CLOCKS_PER_SEC` of 1,000,000). +/// This is a general implementation based on boost::chrono. It should probably be fine for +/// most platforms. /// class Timer { @@ -137,7 +125,7 @@ class Timer /// /// @return Elapsed CPU time in milliseconds. /// - inline POV_LONG ElapsedProcessCPUTime() const { return ElapsedRealTime(); } + POV_LONG ElapsedProcessCPUTime() const; /// Report CPU time consumed by current thread. /// @@ -154,7 +142,7 @@ class Timer /// /// @return Elapsed CPU time in milliseconds. /// - inline POV_LONG ElapsedThreadCPUTime() const { return ElapsedProcessCPUTime(); } + POV_LONG ElapsedThreadCPUTime() const; /// Reset the timer. /// @@ -168,7 +156,7 @@ class Timer /// @return `true` if @ref ElapsedProcessCPUTime() does indeed report per-thread CPU time /// consumption. /// - inline bool HasValidProcessCPUTime() const { return false; } + bool HasValidProcessCPUTime() const; /// Report whether per-thread measurement of CPU time is supported. /// @@ -178,12 +166,27 @@ class Timer /// @return `true` if @ref ElapsedThreadCPUTime() does indeed report per-thread CPU time /// consumption. /// - inline bool HasValidThreadCPUTime() const { return false; } + bool HasValidThreadCPUTime() const; private: /// real time at last reset - boost::xtime mRealTimeStart; +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + boost::chrono::steady_clock::time_point mRealTimeStart; +#else + boost::chrono::system_clock::time_point mRealTimeStart; +#endif + +#ifdef BOOST_CHRONO_HAS_PROCESS_CLOCKS + /// process CPU time at last reset + boost::chrono::process_real_cpu_clock::time_point mProcessTimeStart; +#endif + +#ifdef BOOST_CHRONO_HAS_THREAD_CLOCK + /// thread time at last reset + boost::chrono::thread_clock::time_point mThreadTimeStart; +#endif + }; #endif // POV_USE_DEFAULT_TIMER diff --git a/unix/config/ax_boost_chrono.m4 b/unix/config/ax_boost_chrono.m4 new file mode 100644 index 000000000..576376938 --- /dev/null +++ b/unix/config/ax_boost_chrono.m4 @@ -0,0 +1,118 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_CHRONO +# +# DESCRIPTION +# +# Test for Chrono library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CHRONO_LIB) +# +# And sets: +# +# HAVE_BOOST_CHRONO +# +# LICENSE +# +# Copyright (c) 2012 Xiyue Deng +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +AC_DEFUN([AX_BOOST_CHRONO], +[ + AC_ARG_WITH([boost-chrono], + AS_HELP_STRING([--with-boost-chrono@<:@=special-lib@:>@], + [use the Chrono library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-chrono=boost_chrono-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_chrono_lib="" + else + want_boost="yes" + ax_boost_user_chrono_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Chrono library is available, + ax_cv_boost_chrono, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::chrono::system_clock::time_point time;]])], + ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_chrono" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_CHRONO,,[define if the Boost::Chrono library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_chrono_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + if test "x$link_chrono" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_chrono*.dll* $BOOSTLIBDIR/boost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_chrono.*\)\.dll.*$;\1;' -e 's;^\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_chrono_lib boost_chrono-$ax_boost_user_chrono_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the library!) + fi + if test "x$link_chrono" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) diff --git a/unix/configure.ac b/unix/configure.ac index 8f111e8c3..3d16a3c6d 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -5,7 +5,7 @@ # # --------------------------------------------------------------------------- # Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -# Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd. +# Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. # # POV-Ray is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -58,6 +58,7 @@ m4_include([unix/config/acx_pthread.m4]) m4_include([unix/config/ax_arg_enable.m4]) m4_include([unix/config/ax_arg_with.m4]) m4_include([unix/config/ax_boost_base.m4]) +m4_include([unix/config/ax_boost_chrono.m4]) m4_include([unix/config/ax_boost_thread.m4]) m4_include([unix/config/ax_test_compiler_flags.m4]) m4_include([unix/config/ax_check_lib.m4]) @@ -335,6 +336,15 @@ if test $boost_thread_links != '1'; then AC_MSG_FAILURE([cannot link with the boost thread library]) fi +AX_BOOST_CHRONO + +# FIXME: Boost::Chrono can be used header-only... Do we want to try that? +if test x"$ax_cv_boost_thread" = x"yes"; then + LIBS="$BOOST_CHRONO_LIB $LIBS" +else + AC_MSG_ERROR([cannot find a suitable boost::chrono library]) +fi + AC_DEFINE([USE_OFFICIAL_BOOST], [], [Use the official Boost libraries.]) # Intel Math Kernel library @@ -346,9 +356,6 @@ test x"$ac_cv_lib_mkl_sin" = x"no" && LDFLAGS="$pov_save_ldflags" # libm AC_CHECK_LIB([m], [sin]) -# real-time clock -AC_CHECK_LIB([rt], [clock_gettime]) - # libz; required library for distributable builds AC_MSG_CHECKING([whether to use the ZLIB library]) if test x"$pov_no_distrib" = x"yes" && test x"$with_zlib" = x"no"; then @@ -634,29 +641,6 @@ if test x"$enable_io_restrictions" != x"no"; then ) fi -# nanosleep -AC_CHECK_FUNCS([nanosleep]) - -# usleep and related -AC_CHECK_FUNCS([usleep]) -AC_CHECK_TYPES([useconds_t]) - -# clock_gettime and related -AC_CHECK_FUNCS([clock_gettime]) -AC_CHECK_DECLS([CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID], - [], [], [[#include ]] -) -AC_CHECK_TYPES([clockid_t], [], [], [[#include ]]) - -# getrusage and related -AC_CHECK_FUNCS([getrusage]) -AC_CHECK_DECLS([RUSAGE_SELF, RUSAGE_THREAD, RUSAGE_LWP], - [], [], [[#include ]] -) - -# gettimeofday -AC_CHECK_FUNCS([gettimeofday]) - # asinh and friends (requires libm) AC_CHECK_FUNCS([asinh], [], diff --git a/unix/povconfig/syspovconfigbase.h b/unix/povconfig/syspovconfigbase.h index 9323d902b..3154f27b8 100644 --- a/unix/povconfig/syspovconfigbase.h +++ b/unix/povconfig/syspovconfigbase.h @@ -11,7 +11,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -44,26 +44,8 @@ #define POV_PATH_SEPARATOR '/' #define IFF_SWITCH_CAST (long) -// Our Unix-specific implementation of the Delay() function currently relies on the presence of -// the nanosleep() or usleep() functions. If we have neither of those, we're falling back to -// POV-Ray's platform-independent default implementation. -#if defined(HAVE_NANOSLEEP) || defined(HAVE_USLEEP) - #define POV_USE_DEFAULT_DELAY 0 -#else - #define POV_USE_DEFAULT_DELAY 1 -#endif - -// Our Unix-specific implementation of the Timer class currently relies on the presence of the -// clock_gettime() or gettimeofday() functions, in order to measure at least wall-clock time. If we -// have neither of those, we're falling back to POV-Ray's platform-independent default -// implementation. -// (Note that when it comes to measuring CPU time, we're still as good as the default if we fall -// back to reporting wall clock time.) -#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY) - #define POV_USE_DEFAULT_TIMER 0 -#else - #define POV_USE_DEFAULT_TIMER 1 -#endif +#define POV_USE_DEFAULT_DELAY 1 +#define POV_USE_DEFAULT_TIMER 1 // The default Path::ParsePathString() suits our needs perfectly. #define POV_USE_DEFAULT_PATH_PARSER 1 diff --git a/vfe/unix/vfeplatform.cpp b/vfe/unix/vfeplatform.cpp index e522456c3..38f408b4e 100644 --- a/vfe/unix/vfeplatform.cpp +++ b/vfe/unix/vfeplatform.cpp @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -41,15 +41,10 @@ // C++ variants of C standard headers #include #include -#ifdef HAVE_TIME_H -# include -#endif // other library headers +#include #include -#ifdef HAVE_SYS_TIME_H -# include -#endif #ifdef HAVE_SYS_WAIT_H # include #endif @@ -202,21 +197,8 @@ namespace vfePlatform // in the session. POV_LONG vfeUnixSession::GetTimestamp(void) const { - POV_LONG timestamp = 0; // in milliseconds -#ifdef HAVE_CLOCK_GETTIME - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) == 0) - timestamp = (POV_LONG) (1000)*ts.tv_sec + ts.tv_nsec/1000000; - else -#endif -#ifdef HAVE_GETTIMEOFDAY - { - struct timeval tv; // seconds + microseconds since the Epoch (1970-01-01) - if (gettimeofday(&tv, NULL) == 0) - timestamp = (POV_LONG) (1000)*tv.tv_sec + tv.tv_usec/1000; - } -#endif -// FIXME: add fallback using boost::xtime() + POV_LONG timestamp = static_cast(boost::chrono::duration_cast + (boost::chrono::system_clock::now().time_since_epoch()).count()); // in milliseconds timestamp += m_TimestampOffset; if (timestamp < m_LastTimestamp) { diff --git a/windows/povconfig/syspovconfigbase.h b/windows/povconfig/syspovconfigbase.h index 704c23ae2..03b29349b 100644 --- a/windows/povconfig/syspovconfigbase.h +++ b/windows/povconfig/syspovconfigbase.h @@ -11,7 +11,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -48,11 +48,8 @@ #define POV_DEBUG 0 #endif -// Windows provides a platform-specific mechanism to let a task wait for a specified time. -#define POV_USE_DEFAULT_DELAY 0 - -// Windows provides platform-specific mechanisms to measure both wall-clock and CPU time. -#define POV_USE_DEFAULT_TIMER 0 +#define POV_USE_DEFAULT_DELAY 1 +#define POV_USE_DEFAULT_TIMER 1 // Windows requires platform-specific parsing of path name strings. #define POV_USE_DEFAULT_PATH_PARSER 0 diff --git a/windows/vs10/povplatform.vcxproj b/windows/vs10/povplatform.vcxproj index b579a0b21..0390b1503 100644 --- a/windows/vs10/povplatform.vcxproj +++ b/windows/vs10/povplatform.vcxproj @@ -326,7 +326,6 @@ - @@ -335,7 +334,6 @@ - diff --git a/windows/vs10/povplatform.vcxproj.filters b/windows/vs10/povplatform.vcxproj.filters index 25b23895c..4d4d4022d 100644 --- a/windows/vs10/povplatform.vcxproj.filters +++ b/windows/vs10/povplatform.vcxproj.filters @@ -31,9 +31,6 @@ Platform Source\x86 - - Platform Source\Windows - Platform Source\Windows @@ -51,9 +48,6 @@ Platform Headers\x86 - - Platform Headers\Windows - Platform Headers\Windows