KpeHDeJIb
> Нет гарантий.
У QPC нет гарантий только если баги на уровне хала или биоса. Внезапно, если у тебя кривое железо - нормально работать не будет. На кривом железе вообще нет гарантий что что-то будет нормально работать.
@!!ex
> Внезапно, если у тебя кривое железо - нормально работать не будет.
Внезапно. Половина железа на рынке кривое. Внезапно!
KpeHDeJIb
Не покупай железо на черном рынке в китае.
Сейчас найти железо, которое бы криво работало с QPC - мало реально. Были у АМд проблемы, сам с ними сталкивался, уже давно нету, кстати.
меня когда торкнуло я вот такую фигню написал.
namespace core { namespace time { struct STimerInfo { friend class CTimerMult; public: inline void clearCount(); inline uint64 getCountTicks( ); inline uint64 getFrameTicks( ); inline uint64 getTicksPerSecond( ); inline double getFrameTicksD( ); inline double getFrameSecondD( ); inline double getCountSecondD( ); inline uint64 getResidueTicks( ); inline uint64 getResiduePerTicks( ); inline double getResidueTicksD( ); private: inline STimerInfo( ); inline ~STimerInfo( ); uint64 _countTicks; uint64 _frameTicks; uint64 _ticksPerSecond; double _countSecondD; double _frameTicksD; double _frameSecondD; uint64 _residueTicks; uint64 _residuePerTicks; double _residueTicksD; }; struct STimerSysInfo { friend class CTimerSys; friend class CTimerMult; public: inline uint64 getFrameTicks( ); inline uint64 getTicksPerSecond( ); inline double getFrameSecondD( ); private: inline STimerSysInfo( ); inline ~STimerSysInfo( ); private: uint64 _frameTicks; uint64 _ticksPerSecond; double _frameSecondD; }; class CTimerSys { public: CTimerSys( ); ~CTimerSys( ); void scan( ); STimerSysInfo info; private: LARGE_INTEGER _timeStart,_timeFrequency; }; class CTimerMult { public: CTimerMult( const uint64& ticksPerSecond); ~CTimerMult( ); void elapsedTime( STimerSysInfo& timerInfo); STimerInfo info; }; }//time }//core
Господа, обёртка над QPC есть в MSDN:
http://msdn.microsoft.com/en-us/library/ms644904(v=vs.85).aspx
Немного допиливания напильником и ок.
Нашел в одном OpenSource проекте вот этот код
uint32_t GetTicks() { #ifdef WIN32 // don't use GetTickCount anymore because it's not accurate enough (~16ms resolution) // don't use QueryPerformanceCounter anymore because it isn't guaranteed to be strictly increasing on some systems and thus requires "smoothing" code // use timeGetTime instead, which typically has a high resolution (5ms or more) but we request a lower resolution on startup return timeGetTime( ); #elif __APPLE__ uint64_t current = mach_absolute_time( ); static mach_timebase_info_data_t info = { 0, 0 }; // get timebase info if( info.denom == 0 ) mach_timebase_info( &info ); uint64_t elapsednano = current * ( info.numer / info.denom ); // convert ns to ms return elapsednano / 1e6; #else uint32_t ticks; struct timespec t; clock_gettime( CLOCK_MONOTONIC, &t ); ticks = t.tv_sec * 1000; ticks += t.tv_nsec / 1000000; return ticks; #endif }
Смутила строчка don't use QueryPerformanceCounter anymore because it isn't guaranteed to be strictly increasing on some systems and thus requires "smoothing" code.
Кто что думает по этому поводу?
dev
> Смутила строчка don't use QueryPerformanceCounter
> Кто что думает по этому поводу?
Никто ничего не думает. Просто не используют. Если пишешь что-то для себя - ради бога. Если что-то глобальное - зачем тебе лишние проблемы? timeBeginPeriod(1) для игр хватает за глаза. Тем более с нынешним засильем низкого фпс.
entryway
> Просто не используют.
Мы используем. имели проблемы только на АМД, но это было давно.
entryway
> timeBeginPeriod(1) для игр хватает за глаза.
У него все равно точность 16 мс. Это мало.
@!!ex
> У него все равно точность 16 мс. Это мало.
возможно timeBeginPeriod(1) работает иначе
вот в этой статье есть:
В обертке не учитывается точность таймера.
Моя обертка:
class CTIMER { public: PBL_INLINE CTIMER(); PBL_INLINE VOID Reset( ); // Функция возвращает время с момента запуска таймера (в мс) PBL_INLINE F64 GetRealTime( ) const; PBL_INLINE F64 GetDeltaTime( ); private: PBL_ALIGN( 16) F64 m_Resolution; PBL_ALIGN( 16) S64 m_nStartTime; PBL_ALIGN( 16) F64 m_LastTime; }; /////////////////////////////////////////////////////////////////////////////////////////////////// CTIMER::CTIMER( ) : m_LastTime( 0) { PBL_ALIGN( 16) S64 nFreq; ::QueryPerformanceFrequency( ( PLARGE_INTEGER)&nFreq); m_Resolution = 1000.0 / ( F64)nFreq; ::QueryPerformanceCounter( ( PLARGE_INTEGER)&m_nStartTime); } /////////////////////////////////////////////////////////////////////////////////////////////////// VOID CTIMER::Reset( ) { m_LastTime = GetRealTime( ); } /////////////////////////////////////////////////////////////////////////////////////////////////// F64 CTIMER::GetRealTime( ) const { PBL_ALIGN( 16) S64 nCurTime; ::QueryPerformanceCounter( ( PLARGE_INTEGER)&nCurTime); return m_Resolution*( F64)( nCurTime-m_nStartTime); } /////////////////////////////////////////////////////////////////////////////////////////////////// F64 CTIMER::GetDeltaTime( ) { PBL_ALIGN( 16) F64 CurTime( GetRealTime( )); PBL_ALIGN( 16) F64 m_DeltaTime( CurTime-m_LastTime); m_LastTime = CurTime; return m_DeltaTime; }
Ну и ужасы здесь написаны. На самом деле все намного проще (делюсь своим классом типа :))
class IntervalTimer { public: IntervalTimer(bool runNow) : _startTime( 0.0f), _endTime( 0.0f) { if ( runNow) run( ); } void run( ) { _runTime = queryTime( ); _startTime = _runTime; } float lap( ) { _endTime = queryTime( ); float dt = _endTime - _startTime; _startTime = _endTime; return dt; } float duration( ) { return queryTime( ) - _runTime; } private: float _runTime; float _startTime; float _endTime; };
Использование:
IntervalTimer timer(true); ... std::cout << " done (" << timer.lap( ) << " msec) " << std::endl << "Computing tangents ... "; ... std::cout << " done (" << timer.lap( ) << " msec) " << std::endl << "Gathering data..."; ... std::cout << " done (" << timer.lap( ) << " msec) " << std::endl;
Правка: queryTime - платформеннозависимое получение текущего времени
Sergio
> Правка: queryTime - платформеннозависимое получение текущего времени
А поподробнее про эту функцию.
Под виндой:
float queryTime() { __int64 COUNTER; __int64 FREQ; QueryPerformanceCounter( ( LARGE_INTEGER*)&COUNTER); QueryPerformanceFrequency( ( LARGE_INTEGER*)&FREQ); return static_cast<float>( static_cast<double>( COUNTER) / static_cast<double>( FREQ)); }
Под айфоном:
double __queryTime() { timeval tv; gettimeofday( &tv, 0); return static_cast<double>( tv.tv_sec) + static_cast<double>( tv.tv_usec) / 1000000.0; } float et::queryTime( ) { if ( !startTimeInitialized) { startTime = __queryTime( ); startTimeInitialized = true; }; return static_cast<float>( __queryTime( ) - startTime); }
Sergio
> Sergio
ну это неинтересно все только интервал.
core::time::CTimerSys timeSys; //сам таймер core::time::CTimerMult timerAnimFire(32,60); // таймер 32 тика в 60сек. core::time::CTimerMult timerAnim( 24,60); // таймер 24 тика в 60сек. timeSys.scan( ); timerAnimFire.elapsedTime( timeSys.info ); timerAnim.elapsedTime( timeSys.info ); .... timeSys.scan( ); timerAnimFire.elapsedTime( timeSys.info ); timerAnim.elapsedTime( timeSys.info ); printf( "%i",timeSys.info.getFrameSecondD( ) ) ;// сколько секунд в фрейме printf( "%f",timeSys.info.getFrameTicks( ) ) ;// сколько тиков в фрейме printf( "%i",timeSys.info.getTicksPerSecond( ) ) ;// сколько тиков в в секунде. константа (1<<32);
timerAnimFire.frame.gatTicksD();// сколько ТИКОВ во фрейме.
timerAnimFire.ticks.gatTicks();//сколько во фрейме было тиков с учетом НАКОПЛЕНИЯ ОСТАТКА.
timerAnimFire.ticks.gatTicksD();//сколько во фрейме было тиков с учетом накопления остатка. дробная.
timerAnimFire.ticks.gatResidueD();// gatTicksD() - gatTicks().
например если у нас анимация каждые 30кадров в сек.
то timerAnimFire.ticks.gatTicks() на тот фрейм в котором произошел переход между секундами то даст 1, если было 2 перехода то даст 2 ..
timerAnimFire.ticks.gatResidueD() легко использовать для интерполяции между тиками чего либо.
особенность что это считается на целочисленной логики и таймера CTimerMult (1,60) / CTimerMult(10,60), CTimerMult(3,60)... сработают одновременно все на 60сек.
удобно в одном месте менять скорость таймеров.
Тема в архиве.