简体   繁体   English

Win32 API计时器

[英]Win32 API timers

I was using the system timer (clock() function, see time.h) to time some serial and USB comms. 我正在使用系统定时器(clock()函数,请参阅time.h)来计算一些串行和USB通信。 All I needed was approx 1ms accurace. 我需要的只有大约1毫米的准备。 The first thing I noticed is that individual times can be out (plus or minus) 10ms. 我注意到的第一件事是个别时间可以超出(加或减)10毫秒。 Timing a number of smaller events led to less accurate timing as events went by. 随着事件的发生,对一些较小的事件进行定时导致时间不准确。 Aggregate timing was slightly better. 总体时间略好一些。 After a bit of a root on MSDN etc I stumbled across the timer in windows multi-media library (timeGetTime(), see MMSystem.h). 在MSDN上有点根后,我偶然发现了Windows多媒体库中的计时器(timeGetTime(),参见MMSystem.h)。 This was much better with decent accuracy to the 1ms level. 这对于1ms级别来说具有良好的准确性要好得多。

Weirdness then ensued, after initially working flawlessy for days (lovely logs with useful timings) it all went pearshaped as this API also started showing this odd granularity (instead of a bunch of small comms messages taking 3ms,2ms,3ms,2ms, 3ms etc. it came out as 0ms, 0ms, 0ms, 0ms, 15ms etc. Rebooting the PC restored nomal accuarce but at some indeterminate time (after an hour or so) the anomoly returned. 然后发生了奇怪的事情,在最初工作完美无瑕几天(有用时间的可爱日志)后,所有这些都变成了梨形,因为这个API也开始显示这种奇怪的粒度(而不是一堆小的通信消息需要3ms,2ms,3ms,2ms,3ms等它出现了0ms,0ms,0ms,0ms,15ms等。重新启动PC恢复了正常的准确性,但在一些不确定的时间(一小时左右之后),anomoly返回。

Anyone got any idea or suggestions of how to get this level of timing accuracy on Windows XP (32bit Pro, using Visual Studio 2008). 任何人都对如何在Windows XP(32位Pro,使用Visual Studio 2008)上获得这种级别的计时准确性有任何想法或建议。

My little timing class: 我的小时间班:

class TMMTimer
{
public:
    TMMTimer( unsigned long msec);
    TMMTimer();

    void Clear() { is_set = false; }
    void Set( unsigned long msec=0);

    bool Expired();
    unsigned long Elapsed();

private:
    unsigned long when;
    int roll_over;
    bool is_set;
};



/** Main constructor.
 */
TMMTimer::TMMTimer()
{
    is_set = false;
}




/** Main constructor.
 */
TMMTimer::TMMTimer( unsigned long msec)
{
    Set( msec);
}




/** Set the timer.
 *
 * @note   This sets the timer to some point in the future.
 *         Because the timer can wrap around the function sets a
 *         rollover flag for this condition which is checked by the
 *         Expired member function.
 */
void TMMTimer::Set( unsigned long msec /*=0*/)
{
    unsigned long now = timeGetTime();       // System millisecond counter.

    when = now + msec;

    if (when < now)
        roll_over = 1;
    else
        roll_over = 0;

    is_set = true;
}




/** Check if timer expired.
 *
 * @return  Returns true if expired, else false.
 *
 * @note    Also returns true if timer was never set. Note that this
 *          function can handle the situation when the system timer
 *          rolls over (approx every 47.9 days).
 */
bool TMMTimer::Expired()
{
    if (!is_set)
        return true;

    unsigned long now = timeGetTime();       // System millisecond counter.

    if (now > when)
    {
        if (!roll_over)
        {
            is_set = false;
            return true;
        }
    }
    else
    {
        if (roll_over)
            roll_over = false;
    }

    return false;
}




/** Returns time elapsed since timer expired.
 *
 * @return  Time in milliseconds, 0 if timer was never set.
 */
unsigned long TMMTimer::Elapsed()
{
    if (!is_set)
        return 0;

    return timeGetTime()-when;
}

Did you call timeBeginPeriod(1); 你有没有打电话给timeBeginPeriod(1); to set the multimedia resolution to 1 millisecond? 将多媒体分辨率设置为1毫秒? The multimedia timer resolution is system-global, so if you didn't set it yourself, chances are that you started after something else had called it, then when that something else called timeEndPeriod() , the resolution went back to the system default (which is normally 10 ms, if memory serves). 多媒体计时器分辨率是系统全局的,所以如果你没有自己设置,很可能是你在其他人调用它之后开始,然后当其他东西调用timeEndPeriod() ,分辨率又恢复到系统默认值(通常是10毫秒,如果内存服务)。

Others have advised using QueryPerformanceCounter() . 其他人建议使用QueryPerformanceCounter() This does have much higher resolution, but you still need to be careful. 这确实具有更高的分辨率,但您仍需要小心。 Depending on the kernel involved, it can/will use the x86 RDTSC function, which is a 64-bit counter of instruction cycles. 根据所涉及的内核,它可以/将使用x86 RDTSC函数,该函数是指令周期的64位计数器。 For better or worse, on a CPU whose clock rate varies (which started on laptops, but is now common almost everywhere) the relationship between the clock count and wall time varies right along with the clock speed. 无论好坏,在时钟频率变化的CPU上(从笔记本电脑开始,但现在几乎无处不在),时钟计数和挂壁时间之间的关系随时钟速度而变化。 If memory serves, if you force Windows to install with the assumption that there are multiple physical processors (not just multiple cores), you'll get a kernel in which QueryPerformanceCounter() will read the motherboard's 1.024 MHz clock instead. 如果内存服务,如果强制Windows安装时假设有多个物理处理器(而不仅仅是多个内核),那么你将获得一个内核,其中QueryPerformanceCounter()将读取主板的1.024 MHz时钟。 This reduces resolution compared to the CPU clock, but at least the speed is constant (and if you only need 1 ms resolution, it should be more than adequate anyway). 与CPU时钟相比,这会降低分辨率,但至少速度是恒定的(如果您只需要1 ms的分辨率,那么它应该是足够的)。

If you want high resolution timing on Windows, you should consider using QueryPerformanceFrequency and QueryPerformanceCounter . 如果您想在Windows上进行高分辨率计时,则应考虑使用QueryPerformanceFrequencyQueryPerformanceCounter

These will provide the most accurate timings available on Windows, and should be much more "stable" over time. 这些将提供Windows上最准确的时序,并且随着时间的推移应该更加“稳定”。 QPF gives you the number of counts/second, and QPC gives you the current count. QPF为您提供计数/秒,QPC为您提供当前计数。 You can use this to do very high resolution timings on most systems (fraction of ms). 您可以使用它在大多数系统上执行非常高分辨率的计时(ms的分数)。

Check out the high resolution timers from the Win32 API. 查看Win32 API中的高分辨率计时器。

http://msdn.microsoft.com/en-us/library/ms644904(VS.85).aspx http://msdn.microsoft.com/en-us/library/ms644904(VS.85).aspx

You can use it to usually get microsecond resolution timers. 您可以使用它来获得微秒级的分辨率计时器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM