Windows计时器功能的性能

Performance of Windows timer functions

本文关键字:性能 功能 计时器 Windows      更新时间:2023-10-16

我尝试使用timeSetEvent每500ms调用一个看门狗函数。

通常情况下,看门狗被调用时没有任何问题。然而,当DVD插入驱动器时,由于系统正忙于读取磁盘,我在长达8秒的时间内不会收到回调。使用WindowsQueue计时器,情况并没有那么糟糕,我有4秒的时间。

我最后一次尝试是将线程优先级设置为时间关键型,然后休眠500毫秒,但回调在8秒钟内没有发生。

我仍然在运行XP,但我不知道在以后的操作系统中所做的更改会使它变得更好。

我以插入DVD为例。如果可能的话,我希望代码对其他条件具有鲁棒性。

非常感谢任何建议。

我们发现的从Windows获得良好计时性能的最佳方法是完全避免计时器功能,并自行滚动;只是坐在一个紧张的循环中,吃掉CPU,直到下一个计时器事件的时间到来。QueryPerformanceCounter似乎是获得快速、高分辨率时间的最佳方式。尽你所能让运行这个循环的线程拥有自己的CPU核心,它将坚持使用它,不会有任何其他占用CPU时间的东西。

但请注意:

  • 时机还远远不够完美。这种方法让你的大部分周期都有合理的计时(TM),但偶尔会出现故障,大多在100毫秒内,但偶尔也会在几秒钟内
  • 当然,这会给你的CPU利用率设置一个下限
  • 我仍然不知道你的DVD驱动程序会如何运行

一般来说,如果你需要准确的计时,Windows不是这样做的地方。

您研究过RegisterWaitForSingleObject函数吗(http://msdn.microsoft.com/en-us/library/windows/desktop/ms685061%28v=vs.85%29.aspx)?

您可以尝试此示例代码,该代码旨在在单独的线程中使用,以便在Windows XP上以固定频率运行,最高可达400hz(其中睡眠(1)可能需要大约2ms)。当一个新卷(在这种情况下是DVD)准备就绪时,似乎会有一个系统范围的延迟,但如果打开外部USB硬盘驱动器,也会发生类似的延迟。似乎Windows XP开始扫描新卷,锁定了相当多的系统,甚至这个代码示例也可能受到影响,因为它使用睡眠(1)来减少cpu开销。您可以删除Sleep(1)代码,该代码将使其中一个cpu内核保持100%运行,但插入DVD仍有可能将其搞砸。

/* code for a thread to run at fixed frequency */
typedef unsigned long long UI64;        /* unsigned 64 bit int */
#define FREQ    2                       /* frequency (500 ms) */
LARGE_INTEGER liPerfTemp;               /* used for query */
UI64 uFreq = FREQ;                      /* process frequency */
UI64 uOrig;                             /* original tick */
UI64 uWait;                             /* tick rate / freq */
UI64 uRem = 0;                          /* tick rate % freq */
UI64 uPrev;                             /* previous tick based on original tick */
UI64 uDelta;                            /* current tick - previous */
UI64 u2ms;                              /* 2ms of ticks */
UI64 i;
    /* ... */ /* wait for some event to start thread */
    timeBeginPeriod(1);                 /* set period to 1ms */
    Sleep(128);                         /* wait for it to stabilize */
    u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);
    QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
    uOrig = uPrev = liPerfTemp.QuadPart;
    for(i = 0; i < (uFreq*30); i++){
        /* update uWait and uRem based on uRem */
        uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
        uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
        /* wait for uWait ticks */
        while(1){
            QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
            uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
            if(uDelta >= uWait)
                break;
            if((uWait - uDelta) > u2ms)
                Sleep(1);
        }
        if(uDelta >= (uWait*2))
            dwLateStep += 1;
        uPrev += uWait;
        /* fixed frequency code goes here */
        /*  along with some type of break when done */
    }
    timeEndPeriod(1);                   /* restore period */