PerformanceTimer.hh 9.4 KB
Newer Older
1 2 3 4 5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
Robert Menzel's avatar
Robert Menzel committed
6

7 8
#ifndef ACGL_UTILS_PERFORMANCETIMER_HH
#define ACGL_UTILS_PERFORMANCETIMER_HH
Robert Menzel's avatar
Robert Menzel committed
9 10 11 12 13 14

/*
 * 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.
Robert Menzel's avatar
Robert Menzel committed
15 16
 *             NOTE: The system time might get changed during the application runtime (if someone sets the
 *             time manually).
Robert Menzel's avatar
Robert Menzel committed
17
 * ProcessTime is based on the runtime of the process/application.
Robert Menzel's avatar
Robert Menzel committed
18 19
 *             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.
Robert Menzel's avatar
Robert Menzel committed
20
 * ThreadTime  is based on the time the thread has run in which it is called.
Robert Menzel's avatar
Robert Menzel committed
21 22 23
 *             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.
 *
Robert Menzel's avatar
Robert Menzel committed
24 25 26 27 28
 *
 * Just use it like:
 *
 * ProcessTime t; // automatic reset
 * slowFunction();
29
 * log() << "function took " << t.getTimeInSecondsD() << " seconds, ";
Robert Menzel's avatar
Robert Menzel committed
30 31
 * t.reset();
 * fastFunction();
32
 * log() << "other function took " << t.getTimeInNanoseconds() << " nanoseconds";
Robert Menzel's avatar
Robert Menzel committed
33 34
 */

35 36 37
#include <ACGL/ACGL.hh>
#include <iostream>

Robert Menzel's avatar
Robert Menzel committed
38
// for the system independent fallback:
39 40
#include <ctime>

Robert Menzel's avatar
Robert Menzel committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
// 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



Robert Menzel's avatar
Robert Menzel committed
59 60 61
namespace ACGL{
namespace Utils{

Robert Menzel's avatar
Robert Menzel committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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...
79
    virtual uint64_t getTimeInNanoseconds() = 0;
Robert Menzel's avatar
Robert Menzel committed
80 81

    // 32 bit unsigned int with seconds will overflow after 136 years
82 83
    virtual uint32_t getTimeInSeconds()  = 0;
    virtual double   getTimeInSecondsD() = 0;
Robert Menzel's avatar
Robert Menzel committed
84 85

    // get time diff since last reset:
86
    virtual uint64_t getTimeDiffInNanoseconds() { return getTimeInNanoseconds() - mStartTime; }
Robert Menzel's avatar
Robert Menzel committed
87 88 89 90 91 92 93 94

    // 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!
95
    virtual uint64_t getTimerResolutionInNanoseconds() {
Robert Menzel's avatar
Robert Menzel committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
        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...
117
    uint64_t getTimeInNanoseconds() {
Robert Menzel's avatar
Robert Menzel committed
118 119 120 121
        return clockToNanoseconds( clock() );
    }

    // 32 bit unsigned int with seconds will overflow after 136 years
122
    uint32_t getTimeInSeconds()  {
Robert Menzel's avatar
Robert Menzel committed
123 124 125
        return (uint32_t) getTimeInSecondsD();
    }

126
    double   getTimeInSecondsD() {
Robert Menzel's avatar
Robert Menzel committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
        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() {
142
		static bool warned = false;
143 144 145 146
        if ( !warned ) {
            ACGL::Utils::error() << "No system timer present on this OS - fallback to process time" << std::endl;
            warned = true;
        }
Robert Menzel's avatar
Robert Menzel committed
147 148 149 150 151 152 153
    }
};

// fallback which gives a warning at runtime
class CThreadTimer : public CProcessTimer
{
public:
154 155
	CThreadTimer() : CProcessTimer() {
		static bool warned = false;
156 157 158 159
        if ( !warned ) {
            ACGL::Utils::error() << "No thread timer present on this OS - fallback to process time" << std::endl;
            warned = true;
        }
Robert Menzel's avatar
Robert Menzel committed
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    }
};

///////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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...
178
    uint64_t getTimeInNanoseconds() {
Robert Menzel's avatar
Robert Menzel committed
179 180 181 182 183 184 185 186
        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
187
    uint32_t getTimeInSeconds()  {
Robert Menzel's avatar
Robert Menzel committed
188 189 190 191 192
        timeval t;
        gettimeofday( &t, NULL );
        return (uint32_t) (t.tv_sec);
    }

193
    double   getTimeInSecondsD() {
Robert Menzel's avatar
Robert Menzel committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
        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__

Robert Menzel's avatar
Robert Menzel committed
210
template < clockid_t TIMER_TYPE >
Robert Menzel's avatar
Robert Menzel committed
211
class PosixTimer : public PerformanceTimerInterface
Robert Menzel's avatar
Robert Menzel committed
212 213 214
{
public:

Robert Menzel's avatar
Robert Menzel committed
215
    PosixTimer() : PerformanceTimerInterface() { restart(); }
216
    ~PosixTimer() {}
Robert Menzel's avatar
Robert Menzel committed
217 218

    // set the mStartTime to the current time:
Robert Menzel's avatar
Robert Menzel committed
219
    //inline void restart() { timespec t; clock_gettime( TIMER_TYPE, &t); mStartTime = timespecTo64( t ); }
Robert Menzel's avatar
Robert Menzel committed
220 221 222

    // returns the CPU/Process/Thread time in nanosecounds, a 64 bit unsigned int will overflow after
    // 584 years...
223
    uint64_t getTimeInNanoseconds() { timespec t; clock_gettime( TIMER_TYPE, &t); return timespecTo64(t); }
Robert Menzel's avatar
Robert Menzel committed
224 225

    // 32 bit unsigned int with seconds will overflow after 136 years
226 227
    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); }
Robert Menzel's avatar
Robert Menzel committed
228 229

    // get the system dependent resolution of the timing in nanoseconds
230
    uint64_t getTimerResolutionInNanoseconds() { timespec t; clock_getres( TIMER_TYPE, &t); return timespecTo64(t); }
Robert Menzel's avatar
Robert Menzel committed
231 232 233 234 235 236

private:
    inline uint64_t timespecTo64( const timespec &_time ) const {
        return ( _time.tv_sec*1000000000 + _time.tv_nsec );
    }

237
    inline double timespecToDouble( const timespec &_time ) const {
Robert Menzel's avatar
Robert Menzel committed
238 239 240 241 242 243 244
        return ( _time.tv_sec + _time.tv_nsec/1000000000.0 );
    }

    uint64_t mStartTime;

};

Robert Menzel's avatar
Robert Menzel committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
#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



Robert Menzel's avatar
Robert Menzel committed
284 285 286 287

} // Utils
} // ACGL

288
#endif // ACGL_UTILS_PERFORMANCETIMER_HH