Saxum/extern/acgl/include/ACGL/Utils/PerformanceTimer.hh
2014-10-20 17:31:26 +02:00

289 lines
9.4 KiB
C++

/***********************************************************************
* Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#ifndef ACGL_UTILS_PERFORMANCETIMER_HH
#define ACGL_UTILS_PERFORMANCETIMER_HH
/*
* Three Timers are defined here: SystemTimer, ProcessTimer and ThreadTimer.
* They can be used to do basic time measurements with high accuracy.
*
* SystemTimer is based on the time since 1.1.1970.
* NOTE: The system time might get changed during the application runtime (if someone sets the
* time manually).
* ProcessTime is based on the runtime of the process/application.
* NOTE: This can be the CPU time used by the process so the time reported by this might differ
* from the 'clock at the wall' and thus is not a good basis for e.g. animations.
* ThreadTime is based on the time the thread has run in which it is called.
* NOTE: This can be the CPU time used by the thread so the time reported by this might differ
* from the 'clock at the wall' and thus is not a good basis for e.g. animations.
*
*
* Just use it like:
*
* ProcessTime t; // automatic reset
* slowFunction();
* log() << "function took " << t.getTimeInSecondsD() << " seconds, ";
* t.reset();
* fastFunction();
* log() << "other function took " << t.getTimeInNanoseconds() << " nanoseconds";
*/
#include <ACGL/ACGL.hh>
#include <iostream>
// for the system independent fallback:
#include <ctime>
// C++11
#if (__cplusplus >= 201103L)
#include <chrono>
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// System dependent includes
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#if defined( __linux__) || defined( __APPLE__ )
#include <sys/time.h>
#elif defined( _WIN32 )
// note: _WIN32 is also defined on 64 bit systems!
#endif
namespace ACGL{
namespace Utils{
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Plattform independent timer code and fallbacks:
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// used to define the API for the System specific timers:
class PerformanceTimerInterface
{
public:
PerformanceTimerInterface() {}
virtual ~PerformanceTimerInterface() {}
// set the mStartTime to the current time:
inline void restart() { mStartTime = getTimeInNanoseconds(); }
// returns the time in nanosecounds, a 64 bit unsigned int will overflow after 584 years...
virtual uint64_t getTimeInNanoseconds() = 0;
// 32 bit unsigned int with seconds will overflow after 136 years
virtual uint32_t getTimeInSeconds() = 0;
virtual double getTimeInSecondsD() = 0;
// get time diff since last reset:
virtual uint64_t getTimeDiffInNanoseconds() { return getTimeInNanoseconds() - mStartTime; }
// 32 bit unsigned int with seconds will overflow after 136 years
inline uint32_t getTimeDiffInSeconds() { return getTimeInSeconds() - (mStartTime/1000000000); }
inline double getTimeDiffInSecondsD() { return getTimeInSecondsD() - (mStartTime/1000000000.0); }
// get the system dependent resolution of the timing in nanoseconds
// default implementation tests this, better timer implementations should
// query this info from the system API!
virtual uint64_t getTimerResolutionInNanoseconds() {
uint64_t t0, t1;
t0 = t1 = getTimeInNanoseconds();
while (t0 == t1) t1 = getTimeInNanoseconds();
return (t1-t0);
}
private:
uint64_t mStartTime; // in nano seconds
};
//
// works in all C environments with varying resolution, does only get the time for the
// whole process
class CProcessTimer : public PerformanceTimerInterface
{
public:
CProcessTimer() : PerformanceTimerInterface() { restart(); }
~CProcessTimer() {}
// returns the CPU/Process/Thread time in nanosecounds, a 64 bit unsigned int will overflow after
// 584 years...
uint64_t getTimeInNanoseconds() {
return clockToNanoseconds( clock() );
}
// 32 bit unsigned int with seconds will overflow after 136 years
uint32_t getTimeInSeconds() {
return (uint32_t) getTimeInSecondsD();
}
double getTimeInSecondsD() {
return (double) clock() / (double) CLOCKS_PER_SEC;
}
private:
uint64_t clockToNanoseconds( clock_t _clock )
{
double msec = (double)_clock / (double) CLOCKS_PER_SEC * (1000.0 * 1000.0 * 1000.0);
return (uint64_t) msec;
}
};
// fallback which gives a warning at runtime
class CSystemTimer : public CProcessTimer
{
public:
CSystemTimer() : CProcessTimer() {
static bool warned = false;
if ( !warned ) {
ACGL::Utils::error() << "No system timer present on this OS - fallback to process time" << std::endl;
warned = true;
}
}
};
// fallback which gives a warning at runtime
class CThreadTimer : public CProcessTimer
{
public:
CThreadTimer() : CProcessTimer() {
static bool warned = false;
if ( !warned ) {
ACGL::Utils::error() << "No thread timer present on this OS - fallback to process time" << std::endl;
warned = true;
}
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// General Unix: Can be used on Linux or MacOS (probably other Unices as well) for the system time.
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#if defined( __linux__) || defined( __APPLE__ )
class UnixSystemTimer : public PerformanceTimerInterface
{
public:
UnixSystemTimer() : PerformanceTimerInterface() { restart(); }
~UnixSystemTimer() {}
// returns the CPU/Process/Thread time in nanosecounds, a 64 bit unsigned int will overflow after
// 584 years...
uint64_t getTimeInNanoseconds() {
timeval t;
gettimeofday( &t, NULL );
uint64_t time = t.tv_sec * 1000000000; // sec to nano
time += t.tv_usec * 1000; // micro to nano
return time;
}
// 32 bit unsigned int with seconds will overflow after 136 years
uint32_t getTimeInSeconds() {
timeval t;
gettimeofday( &t, NULL );
return (uint32_t) (t.tv_sec);
}
double getTimeInSecondsD() {
timeval t;
gettimeofday( &t, NULL );
double time = (double) t.tv_sec;
time += t.tv_usec / 1000000.0; // micro to seconds
return time;
}
};
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Linux version is based on Posix timer, note that those are not present on OSX!
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef __linux__
template < clockid_t TIMER_TYPE >
class PosixTimer : public PerformanceTimerInterface
{
public:
PosixTimer() : PerformanceTimerInterface() { restart(); }
~PosixTimer() {}
// set the mStartTime to the current time:
//inline void restart() { timespec t; clock_gettime( TIMER_TYPE, &t); mStartTime = timespecTo64( t ); }
// returns the CPU/Process/Thread time in nanosecounds, a 64 bit unsigned int will overflow after
// 584 years...
uint64_t getTimeInNanoseconds() { timespec t; clock_gettime( TIMER_TYPE, &t); return timespecTo64(t); }
// 32 bit unsigned int with seconds will overflow after 136 years
uint32_t getTimeInSeconds() { timespec t; clock_gettime( TIMER_TYPE, &t); return t.tv_sec; }
double getTimeInSecondsD() { timespec t; clock_gettime( TIMER_TYPE, &t); return timespecToDouble(t); }
// get the system dependent resolution of the timing in nanoseconds
uint64_t getTimerResolutionInNanoseconds() { timespec t; clock_getres( TIMER_TYPE, &t); return timespecTo64(t); }
private:
inline uint64_t timespecTo64( const timespec &_time ) const {
return ( _time.tv_sec*1000000000 + _time.tv_nsec );
}
inline double timespecToDouble( const timespec &_time ) const {
return ( _time.tv_sec + _time.tv_nsec/1000000000.0 );
}
uint64_t mStartTime;
};
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Implementation selection based on OS:
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef __linux__
typedef PosixTimer< ((clockid_t)CLOCK_REALTIME) > SystemTimer;
typedef PosixTimer< ((clockid_t)CLOCK_PROCESS_CPUTIME_ID) > ProcessTimer;
typedef PosixTimer< ((clockid_t)CLOCK_THREAD_CPUTIME_ID) > ThreadTimer;
#elif defined( __APPLE__ )
typedef UnixSystemTimer SystemTimer;
typedef CProcessTimer ProcessTimer;
typedef CThreadTimer ThreadTimer;
//#elif defined( _WIN32 )
// ToDo: on windows a good timer might be implementable with:
// QueryPerformanceFrequency
// QueryPerformanceCounter
// from #include <windows.h>
#else
//
// No good OS specific timers yet implemented / unknown OS, default to standart C versions:
//
typedef CSystemTimer SystemTimer;
typedef CProcessTimer ProcessTimer;
typedef CThreadTimer ThreadTimer;
#endif
} // Utils
} // ACGL
#endif // ACGL_UTILS_PERFORMANCETIMER_HH