Fix timing functions for various platforms.

This commit is contained in:
Pavel Krajcevski 2012-08-30 16:56:42 -04:00
parent 720ad0ac6f
commit d8fc05a763
5 changed files with 193 additions and 66 deletions

View file

@ -12,8 +12,11 @@ SET( HEADERS
# Make sure to add the appropriate stopwatch files... # Make sure to add the appropriate stopwatch files...
SET( HEADERS ${HEADERS} "src/StopWatch.h" ) SET( HEADERS ${HEADERS} "src/StopWatch.h" )
IF( MSVC )
IF( WIN32 )
SET( SOURCES ${SOURCES} "src/StopWatchWin32.cpp" ) SET( SOURCES ${SOURCES} "src/StopWatchWin32.cpp" )
ELSEIF( APPLE )
SET( SOURCES ${SOURCES} "src/StopWatchOSX.cpp" )
ELSE() ELSE()
SET( SOURCES ${SOURCES} "src/StopWatchUnix.cpp" ) SET( SOURCES ${SOURCES} "src/StopWatchUnix.cpp" )
ENDIF() ENDIF()

View file

@ -15,15 +15,20 @@
// //
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
#pragma once // Forward declare the private implementation of the class that will actually implement
// the timing features. This class is defined in each module depending on the platform...
#include "TexCompTypes.h" class StopWatchImpl;
// A simple stopwatch class using Windows' high-resolution performance counters. // A simple stopwatch class using Windows' high-resolution performance counters.
class StopWatch class StopWatch
{ {
public: public:
StopWatch(); StopWatch();
StopWatch(const StopWatch &);
~StopWatch();
StopWatch &operator=(const StopWatch &);
void Start(); void Start();
void Stop(); void Stop();
@ -34,8 +39,5 @@ public:
double TimeInMicroseconds() const; double TimeInMicroseconds() const;
private: private:
uint64 frequency; StopWatchImpl *impl;
uint64 start;
uint64 stop;
int32_ptr affinityMask;
}; };

67
Core/src/StopWatchOSX.cpp Normal file
View file

@ -0,0 +1,67 @@
#include "StopWatch.h"
#include "TexCompTypes.h"
#include <stdlib.h>
#include <string.h>
#include <mach/mach_time.h>
class StopWatchImpl {
public:
uint64 start;
double resolution;
double duration;
StopWatchImpl() {
mach_timebase_info_data_t info;
mach_timebase_info(&info);
resolution = double(info.numer) / double(info.denom);
resolution *= 1e-9;
}
};
StopWatch::StopWatch(const StopWatch &other) {
impl = new StopWatchImpl();
memcpy(impl, other.impl, sizeof(StopWatchImpl));
}
StopWatch &StopWatch::operator=(const StopWatch &other) {
if(impl) {
delete impl;
}
impl = new StopWatchImpl();
memcpy(impl, other.impl, sizeof(StopWatchImpl));
}
StopWatch::~StopWatch() {
delete impl;
}
StopWatch::StopWatch() : impl(new StopWatchImpl) {
Reset();
}
void StopWatch::Start() {
impl->start = mach_absolute_time();
}
void StopWatch::Stop() {
impl->duration = impl->resolution * (double(mach_absolute_time()) - impl->start);
}
void StopWatch::Reset() {
impl->start = impl->duration = 0.0;
}
double StopWatch::TimeInSeconds() const {
return impl->duration;
}
double StopWatch::TimeInMilliseconds() const {
return impl->duration * 1000;
}
double StopWatch::TimeInMicroseconds() const {
return impl->duration * 1000000;
}

View file

@ -1,29 +1,62 @@
#include "StopWatch.h" #include "StopWatch.h"
#include "TexCompTypes.h"
StopWatch::StopWatch() { #include <stdlib.h>
#include <string.h>
#include <time.h>
class StopWatchImpl {
public:
timespec ts;
double timer;
double duration;
};
StopWatch::StopWatch(const StopWatch &other) {
impl = new StopWatchImpl();
memcpy(impl, other.impl, sizeof(StopWatchImpl));
}
StopWatch &StopWatch::operator=(const StopWatch &other) {
if(impl) {
delete impl;
}
impl = new StopWatchImpl();
memcpy(impl, other.impl. sizeof(StopWatchImpl));
}
StopWatch::~StopWatch() {
delete impl;
}
StopWatch::StopWatch() : impl(new StopWatchImpl) {
Reset();
} }
void StopWatch::Start() { void StopWatch::Start() {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(impl->ts));
impl->timer = double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
} }
void StopWatch::Stop() { void StopWatch::Stop() {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(impl->ts));
impl->duration = -(impl->timer) + (double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec));
} }
void StopWatch::Reset() { void StopWatch::Reset() {
impl->timer = impl->duration = 0.0;
memset(impl->ts, 0, sizeof(timespec));
} }
double StopWatch::TimeInSeconds() const { double StopWatch::TimeInSeconds() const {
return impl->duration;
} }
double StopWatch::TimeInMilliseconds() const { double StopWatch::TimeInMilliseconds() const {
return impl->duration * 1000;
} }
double StopWatch::TimeInMicroseconds() const { double StopWatch::TimeInMicroseconds() const {
return impl->duration * 1000000;
} }

View file

@ -16,91 +16,113 @@
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
#include "StopWatch.h" #include "StopWatch.h"
#include "TexCompTypes.h"
#include <cassert> #include <cassert>
// Initialize member variables. class StopWatchImpl {
StopWatch::StopWatch() : uint64 frequency;
frequency(0), uint64 start;
start(0), uint64 stop;
stop(0), uintptr affinityMask;
affinityMask(0)
{ StopWatchImpl() :
// Initialize the performance counter frequency. start(0), stop(0), affinityMask(0)
LARGE_INTEGER perfQuery; {
BOOL supported = QueryPerformanceFrequency(&perfQuery); // Initialize the performance counter frequency.
assert(supported == TRUE); LARGE_INTEGER perfQuery;
this->frequency = perfQuery.QuadPart; BOOL supported = QueryPerformanceFrequency(&perfQuery);
assert(supported == TRUE);
this->frequency = perfQuery.QuadPart;
}
};
StopWatch::StopWatch(const StopWatch &other) {
impl = new StopWatchImpl();
memcpy(impl, other.impl, sizeof(StopWatchImpl));
}
StopWatch &StopWatch::operator=(const StopWatch &other) {
if(impl) {
delete impl;
}
impl = new StopWatchImpl();
memcpy(impl, other.impl. sizeof(StopWatchImpl));
}
StopWatch::~StopWatch() {
delete impl;
} }
// Start the stopwatch. // Start the stopwatch.
void StopWatch::Start() void StopWatch::Start()
{ {
// MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL. // MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL.
// Create an affinity mask for the current processor. // Create an affinity mask for the current processor.
affinityMask = (DWORD_PTR)1 << GetCurrentProcessorNumber(); impl->affinityMask = (DWORD_PTR)1 << GetCurrentProcessorNumber();
HANDLE currThread = GetCurrentThread(); HANDLE currThread = GetCurrentThread();
DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, affinityMask); DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, impl->affinityMask);
assert(prevAffinityMask != 0); assert(prevAffinityMask != 0);
// Query the performance counter. // Query the performance counter.
LARGE_INTEGER perfQuery; LARGE_INTEGER perfQuery;
BOOL result = QueryPerformanceCounter(&perfQuery); BOOL result = QueryPerformanceCounter(&perfQuery);
assert(result); assert(result);
start = perfQuery.QuadPart; impl->start = perfQuery.QuadPart;
// Restore the thread's affinity mask. // Restore the thread's affinity mask.
prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask); prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask);
assert(prevAffinityMask != 0); assert(prevAffinityMask != 0);
} }
// Stop the stopwatch. // Stop the stopwatch.
void StopWatch::Stop() void StopWatch::Stop()
{ {
// MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL. // MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL.
// Use the affinity mask that was created in the Start function. // Use the affinity mask that was created in the Start function.
HANDLE currThread = GetCurrentThread(); HANDLE currThread = GetCurrentThread();
DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, affinityMask); DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, impl->affinityMask);
assert(prevAffinityMask != 0); assert(prevAffinityMask != 0);
// Query the performance counter. // Query the performance counter.
LARGE_INTEGER perfQuery; LARGE_INTEGER perfQuery;
BOOL result = QueryPerformanceCounter(&perfQuery); BOOL result = QueryPerformanceCounter(&perfQuery);
assert(result); assert(result);
stop = perfQuery.QuadPart; impl->stop = perfQuery.QuadPart;
// Restore the thread's affinity mask. // Restore the thread's affinity mask.
prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask); prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask);
assert(prevAffinityMask != 0); assert(prevAffinityMask != 0);
} }
// Reset the stopwatch. // Reset the stopwatch.
void StopWatch::Reset() void StopWatch::Reset()
{ {
start = 0; impl->start = 0;
stop = 0; impl->stop = 0;
affinityMask = 0; impl->affinityMask = 0;
} }
// Get the elapsed time in seconds. // Get the elapsed time in seconds.
double StopWatch::TimeInSeconds() const double StopWatch::TimeInSeconds() const
{ {
// Return the elapsed time in seconds. // Return the elapsed time in seconds.
assert((stop - start) > 0); assert((impl->stop - impl->start) > 0);
return double(stop - start) / double(frequency); return double(impl->stop - impl->start) / double(frequency);
} }
// Get the elapsed time in milliseconds. // Get the elapsed time in milliseconds.
double StopWatch::TimeInMilliseconds() const double StopWatch::TimeInMilliseconds() const
{ {
// Return the elapsed time in milliseconds. // Return the elapsed time in milliseconds.
assert((stop - start) > 0); assert((impl->stop - impl->start) > 0);
return double(stop - start) / double(frequency) * 1000.0; return double(impl->stop - impl->start) / double(frequency) * 1000.0;
} }
// Get the elapsed time in microseconds. // Get the elapsed time in microseconds.
double StopWatch::TimeInMicroseconds() const double StopWatch::TimeInMicroseconds() const
{ {
// Return the elapsed time in microseconds. // Return the elapsed time in microseconds.
assert((stop - start) > 0); assert((impl->stop - impl->start) > 0);
return double(stop - start) / double(frequency) * 1000000.0; return double(impl->stop - impl->start) / double(impl->frequency) * 1000000.0;
} }