Rewrote the implementation of sf::Clock, it now ensures microseconds resolution and monotonicity

This commit is contained in:
Laurent Gomila 2011-12-20 18:47:33 +01:00
parent 5b2648fd8b
commit 3e89dd652f
12 changed files with 505 additions and 344 deletions

View File

@ -62,7 +62,7 @@ public :
Uint32 GetElapsedTime() const; Uint32 GetElapsedTime() const;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Restart the timer /// \brief Restart the clock
/// ///
/// This function puts the time counter back to zero. /// This function puts the time counter back to zero.
/// ///
@ -74,7 +74,7 @@ private :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Uint64 myStartTime; ///< Time of last reset Uint64 myStartTime; ///< Time of last reset, in nanoseconds
}; };
} // namespace sf } // namespace sf

View File

@ -13,7 +13,6 @@ set(SRC
${SRCROOT}/Mutex.cpp ${SRCROOT}/Mutex.cpp
${INCROOT}/Mutex.hpp ${INCROOT}/Mutex.hpp
${INCROOT}/NonCopyable.hpp ${INCROOT}/NonCopyable.hpp
${SRCROOT}/Platform.hpp
${SRCROOT}/Sleep.cpp ${SRCROOT}/Sleep.cpp
${INCROOT}/Sleep.hpp ${INCROOT}/Sleep.hpp
${SRCROOT}/String.cpp ${SRCROOT}/String.cpp
@ -37,10 +36,12 @@ set(SRC
if(WINDOWS) if(WINDOWS)
set(SRC set(SRC
${SRC} ${SRC}
${SRCROOT}/Win32/ClockImpl.cpp
${SRCROOT}/Win32/ClockImpl.hpp
${SRCROOT}/Win32/MutexImpl.cpp ${SRCROOT}/Win32/MutexImpl.cpp
${SRCROOT}/Win32/MutexImpl.hpp ${SRCROOT}/Win32/MutexImpl.hpp
${SRCROOT}/Win32/Platform.cpp ${SRCROOT}/Win32/SleepImpl.cpp
${SRCROOT}/Win32/Platform.hpp ${SRCROOT}/Win32/SleepImpl.hpp
${SRCROOT}/Win32/ThreadImpl.cpp ${SRCROOT}/Win32/ThreadImpl.cpp
${SRCROOT}/Win32/ThreadImpl.hpp ${SRCROOT}/Win32/ThreadImpl.hpp
${SRCROOT}/Win32/ThreadLocalImpl.cpp ${SRCROOT}/Win32/ThreadLocalImpl.cpp
@ -49,10 +50,12 @@ if(WINDOWS)
else() else()
set(SRC set(SRC
${SRC} ${SRC}
${SRCROOT}/Unix/ClockImpl.cpp
${SRCROOT}/Unix/ClockImpl.hpp
${SRCROOT}/Unix/MutexImpl.cpp ${SRCROOT}/Unix/MutexImpl.cpp
${SRCROOT}/Unix/MutexImpl.hpp ${SRCROOT}/Unix/MutexImpl.hpp
${SRCROOT}/Unix/Platform.cpp ${SRCROOT}/Unix/SleepImpl.cpp
${SRCROOT}/Unix/Platform.hpp ${SRCROOT}/Unix/SleepImpl.hpp
${SRCROOT}/Unix/ThreadImpl.cpp ${SRCROOT}/Unix/ThreadImpl.cpp
${SRCROOT}/Unix/ThreadImpl.hpp ${SRCROOT}/Unix/ThreadImpl.hpp
${SRCROOT}/Unix/ThreadLocalImpl.cpp ${SRCROOT}/Unix/ThreadLocalImpl.cpp

View File

@ -26,7 +26,12 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
#include <SFML/System/Platform.hpp>
#if defined(SFML_SYSTEM_WINDOWS)
#include <SFML/System/Win32/ClockImpl.hpp>
#else
#include <SFML/System/Unix/ClockImpl.hpp>
#endif
namespace sf namespace sf
@ -41,14 +46,15 @@ Clock::Clock()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Uint32 Clock::GetElapsedTime() const Uint32 Clock::GetElapsedTime() const
{ {
return static_cast<Uint32>(priv::Platform::GetSystemTime() - myStartTime); Uint64 microseconds = priv::ClockImpl::GetMicroSeconds() - myStartTime;
return static_cast<Uint32>(microseconds / 1000);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Clock::Reset() void Clock::Reset()
{ {
myStartTime = priv::Platform::GetSystemTime(); myStartTime = priv::ClockImpl::GetMicroSeconds();
} }
} // namespace sf } // namespace sf

View File

@ -26,7 +26,12 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <SFML/System/Platform.hpp>
#if defined(SFML_SYSTEM_WINDOWS)
#include <SFML/System/Win32/SleepImpl.hpp>
#else
#include <SFML/System/Unix/SleepImpl.hpp>
#endif
namespace sf namespace sf
@ -34,7 +39,7 @@ namespace sf
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Sleep(Uint32 duration) void Sleep(Uint32 duration)
{ {
priv::Platform::Sleep(duration); priv::SleepImpl(duration);
} }
} // namespace sf } // namespace sf

View File

@ -0,0 +1,64 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/Unix/ClockImpl.hpp>
#ifdef SFML_SYSTEM_MACOS
#include <mach/mach_time.h>
#else
#include <time.h>
#endif
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
Uint64 ClockImpl::GetMicroSeconds()
{
#ifdef SFML_SYSTEM_MACOS
// Mac OS X specific implementation (it doesn't support clock_gettime)
static mach_timebase_info_data_t frequency = {0, 0};
if (frequency.denom == 0)
mach_timebase_info(&frequency);
Uint64 nanoseconds = mach_absolute_time() * frequency.numer / frequency.denom;
return nanoseconds / 1000;
#else
// POSIX implementation
timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return time.tv_sec * 1000000 + time.tv_nsec / 1000;
#endif
}
} // namespace priv
} // namespace sf

View File

@ -22,14 +22,13 @@
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#ifndef SFML_PLATFORMWIN32_HPP #ifndef SFML_CLOCKIMPLUNIX_HPP
#define SFML_PLATFORMWIN32_HPP #define SFML_CLOCKIMPLUNIX_HPP
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Config.hpp> #include <SFML/Config.hpp>
#include <vector>
namespace sf namespace sf
@ -37,28 +36,20 @@ namespace sf
namespace priv namespace priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Gives access to some system-specific low-level functions /// \brief Unix implementaton of sf::Clock
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class Platform class ClockImpl
{ {
public : public :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the current system time /// \brief Get the current time
/// ///
/// \return System time, in milliseconds /// \return Current time, in microseconds
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static Uint64 GetSystemTime(); static Uint64 GetMicroSeconds();
////////////////////////////////////////////////////////////
/// \brief Suspend the execution of the current thread for a specified duration
///
/// \param time Time to sleep, in milliseconds
///
////////////////////////////////////////////////////////////
static void Sleep(Uint32 time);
}; };
} // namespace priv } // namespace priv
@ -66,4 +57,4 @@ public :
} // namespace sf } // namespace sf
#endif // SFML_PLATFORMWIN32_HPP #endif // SFML_CLOCKIMPLUNIX_HPP

View File

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// SFML - Simple and Fast Multimedia Library // SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
// //
// This software is provided 'as-is', without any express or implied warranty. // This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software. // In no event will the authors be held liable for any damages arising from the use of this software.
@ -25,7 +25,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/System/Unix/Platform.hpp> #include <SFML/System/Unix/SleepImpl.hpp>
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
@ -36,21 +36,12 @@ namespace sf
namespace priv namespace priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Uint64 Platform::GetSystemTime() void SleepImpl(Uint32 time)
{
timeval time = {0, 0};
gettimeofday(&time, NULL);
return time.tv_sec * 1000 + time.tv_usec / 1000;
}
////////////////////////////////////////////////////////////
void Platform::Sleep(Uint32 time)
{ {
// usleep is not reliable enough (it might block the // usleep is not reliable enough (it might block the
// whole process instead of just the current thread) // whole process instead of just the current thread)
// so we must use pthread_cond_timedwait instead // so we must use pthread_cond_timedwait instead
// this implementation is inspired from Qt // this implementation is inspired from Qt
// first get the current time // first get the current time

View File

@ -22,11 +22,13 @@
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#ifndef SFML_SLEEPIMPLUNIX_HPP
#define SFML_SLEEPIMPLUNIX_HPP
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/System/Win32/Platform.hpp> #include <SFML/Config.hpp>
#include <windows.h>
namespace sf namespace sf
@ -34,33 +36,16 @@ namespace sf
namespace priv namespace priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Uint64 Platform::GetSystemTime() /// \brief Unix implementation of sf::Sleep
{ ///
static LARGE_INTEGER frequency; /// \param time Time to sleep, in milliseconds
static BOOL useHighPerformanceTimer = QueryPerformanceFrequency(&frequency); ///
if (useHighPerformanceTimer)
{
// High performance counter available : use it
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
return currentTime.QuadPart * 1000 / frequency.QuadPart;
}
else
{
// High performance counter not available: use GetTickCount (less accurate)
return GetTickCount();
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Platform::Sleep(Uint32 time) void SleepImpl(Uint32 time);
{
::Sleep(time);
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf
#endif // SFML_SLEEPIMPLUNIX_HPP

View File

@ -0,0 +1,74 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/Win32/ClockImpl.hpp>
#include <windows.h>
////////////////////////////////////////////////////////////
// Private data
////////////////////////////////////////////////////////////
namespace
{
LARGE_INTEGER GetFrequency()
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return frequency;
}
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
Uint64 ClockImpl::GetMicroSeconds()
{
// Force the following code to run on first core
// (see http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx)
HANDLE currentThread = GetCurrentThread();
DWORD_PTR previousMask = SetThreadAffinityMask(currentThread, 1);
// Get the frequency of the performance counter
// (it is constant across the program lifetime)
static LARGE_INTEGER frequency = GetFrequency();
// Get the current time
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
// Restore the thread affinity
SetThreadAffinityMask(currentThread, previousMask);
// Return the current time as microseconds
return 1000000 * time.QuadPart / frequency.QuadPart;
}
} // namespace priv
} // namespace sf

View File

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// SFML - Simple and Fast Multimedia Library // SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
// //
// This software is provided 'as-is', without any express or implied warranty. // This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software. // In no event will the authors be held liable for any damages arising from the use of this software.
@ -22,8 +22,8 @@
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#ifndef SFML_PLATFORMUNIX_HPP #ifndef SFML_CLOCKIMPLWIN32_HPP
#define SFML_PLATFORMUNIX_HPP #define SFML_CLOCKIMPLWIN32_HPP
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
@ -36,28 +36,20 @@ namespace sf
namespace priv namespace priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Give access to some system-specific low-level functions /// \brief Windows implementaton of sf::Clock
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class Platform class ClockImpl
{ {
public : public :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the current system time /// \brief Get the current time
/// ///
/// \return System time, in milliseconds /// \return Current time, in microseconds
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static Uint64 GetSystemTime(); static Uint64 GetMicroSeconds();
////////////////////////////////////////////////////////////
/// \brief Suspend the execution of the current thread for a specified duration
///
/// \param time Time to sleep, in milliseconds
///
////////////////////////////////////////////////////////////
static void Sleep(Uint32 time);
}; };
} // namespace priv } // namespace priv
@ -65,4 +57,4 @@ public :
} // namespace sf } // namespace sf
#endif // SFML_PLATFORMUNIX_HPP #endif // SFML_CLOCKIMPLWIN32_HPP

View File

@ -22,24 +22,23 @@
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#ifndef SFML_PLATFORM_HPP
#define SFML_PLATFORM_HPP
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Config.hpp> #include <SFML/System/Win32/SleepImpl.hpp>
#include <windows.h>
#if defined(SFML_SYSTEM_WINDOWS) namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
void SleepImpl(Uint32 time)
{
::Sleep(time);
}
#include <SFML/System/Win32/Platform.hpp> } // namespace priv
#else } // namespace sf
#include <SFML/System/Unix/Platform.hpp>
#endif
#endif // SFML_PLATFORM_HPP

View File

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SLEEPIMPLWIN32_HPP
#define SFML_SLEEPIMPLWIN32_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Config.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Windows implementation of sf::Sleep
///
/// \param time Time to sleep, in milliseconds
///
////////////////////////////////////////////////////////////
void SleepImpl(Uint32 time);
} // namespace priv
} // namespace sf
#endif // SFML_SLEEPIMPLWIN32_HPP