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...
SET( HEADERS ${HEADERS} "src/StopWatch.h" )
IF( MSVC )
IF( WIN32 )
SET( SOURCES ${SOURCES} "src/StopWatchWin32.cpp" )
ELSEIF( APPLE )
SET( SOURCES ${SOURCES} "src/StopWatchOSX.cpp" )
ELSE()
SET( SOURCES ${SOURCES} "src/StopWatchUnix.cpp" )
ENDIF()

View file

@ -15,15 +15,20 @@
//
//--------------------------------------------------------------------------------------
#pragma once
#include "TexCompTypes.h"
// 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...
class StopWatchImpl;
// A simple stopwatch class using Windows' high-resolution performance counters.
class StopWatch
{
public:
StopWatch();
StopWatch(const StopWatch &);
~StopWatch();
StopWatch &operator=(const StopWatch &);
void Start();
void Stop();
@ -34,8 +39,5 @@ public:
double TimeInMicroseconds() const;
private:
uint64 frequency;
uint64 start;
uint64 stop;
int32_ptr affinityMask;
StopWatchImpl *impl;
};

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 "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() {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(impl->ts));
impl->timer = double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
}
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() {
impl->timer = impl->duration = 0.0;
memset(impl->ts, 0, sizeof(timespec));
}
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

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