【问题标题】:Windows QueryPerformanceCounter with MinGW C带有 MinGW C 的 Windows QueryPerformanceCounter
【发布时间】:2018-08-27 19:01:55
【问题描述】:

我正在尝试通过拉取 QueryPerformanceCounter (QPC) 来测量串行协议握手的响应时间。我的目标系统是 Asrock D1800b Intel Dual Core 上的 win7,使用最新版本的 MinGw (6.3.0-1) 编译。

为了测试 QPC,我有这个代码:

#include <windows.h>
#include <stdio.h>

void main() 
{
    //performance timers
    LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
    LARGE_INTEGER Frequency;

    QueryPerformanceFrequency(&Frequency);
    for (int i = 0 ; i < 10 ; i++) 
    {
        QueryPerformanceCounter(&StartingTime);
        Sleep(10); //ms
        QueryPerformanceCounter(&EndingTime);
        ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
        ElapsedMicroseconds.QuadPart *= 1000000;                //first scale up counts
        ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;     //then convert to us
        printf("elapsed=%li\n", ElapsedMicroseconds.QuadPart);
    }

}

在目标系统上运行时,我得到:(没有其他负载)

经过=5341
经过=14086
经过=13818
经过=14322
经过=15305
经过=8867
经过=12162
经过=14225
经过=13333
经过=14751

但是在开发系统(Win10,Intel i5)上运行时,我得到了非常一致的结果

经过=11326
经过=11556
经过=12630
经过=11583
经过=11749
经过=12644
经过=12562
经过=11690
经过=11726
经过=11664

以上两个结果都是更大运行的示例。

预期结果在 10000us 以上。

那么,对目标系统上发生的事情有什么想法吗?

【问题讨论】:

  • 目标系统是否经历了一些恒定且相当大的负载变化?
  • 尝试 50 毫秒。 10 ms 接近 sleep 方法的不可靠性极限。好吧,我想 sleep 在这里是为了举例吧?
  • 旁白:注意关于printf中格式类型说明符的编译器警告。
  • 这里的底线是,Windows 不是一个实时操作系统,并且绝对没有作为一个实时操作系统的自负。特别是Sleep() 不能保证它会延迟执行多长时间。你会尽最大努力,但仅此而已。 QueryPerformanceCounter() 相当准确,但如果我可以打个比方,您在这里所做的类似于使用千分尺测量用斧头手工切割的原木的大小。
  • 我知道 windows 不是 RTOS,但我认为最好的睡眠会导致更长的等待,而不是更短的等待。

标签: c performance time timer mingw


【解决方案1】:

您可能需要提高滴答频率,它可能默认为 64hz(每滴答声 15.625 毫秒),以便让 Sleep(10) 按预期工作。您可以将其增加到 1000hz(每滴答声 1 毫秒)。这会增加中断开销,但结果应该更加一致。示例代码片段:

    timeBeginPeriod(1);                     /* set ticker to 1000 hz */
    Sleep(128);                             /* wait for it to settle */
    /* ... benchmark code */
    timeEndPeriod(1);                       /* restore ticker to default */

注意,尽管 Windows 不是实时操作系统,但在 Windows 中可以让线程以固定频率运行而不会出现任何漂移,并尽可能使用 Sleep(1) 来避免 CPU 受限于固定频率线。如果存在竞争线程,则以稍高的优先级运行线程会有所帮助。这通常由需要以固定频率运行的“物理引擎”线程的游戏使用。示例代码包含在这个旧问题的答案中:

How to coordinate threads properly based on a fixed cycle frequency?

基于链接中示例的程序的示例输出,使用 100hz 的固定频率,运行 100 次。每个步骤都有一些变化,但没有整体漂移。

 100 deltas in ms:

  9.99973023  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00676775  10.00002346 
 10.00002346  10.00002346  10.00794067  10.00002346 
  9.99973023  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00618129  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346   9.99973023  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00090315  10.00148961  10.00148961  10.00090315 
 10.00002346  10.00178284  10.00002346  10.00002346 
 10.00295576  10.00002346  10.00882036  10.00500837 
 10.00002346  10.00559483  10.00559483  10.00647452 
 10.00588806  10.00735421  10.00676775  10.00764744 
 10.00002346  10.00002346  10.00823390  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346   9.99973023  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346   9.99973023 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346   9.99973023 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 
 10.00002346  10.00002346  10.00002346  10.00002346 

elapsed time in ms:

1000.000000000000

【讨论】:

  • 我明白你的意思,但这个线程与睡眠精度几乎没有关系,而是了解它与 QPC 的关系。到目前为止,我最好的方法是 Windows 可能会选择不为睡眠调用设置较低的阈值,只是为了尽最大努力完成时间。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2012-10-11
  • 2012-03-01
  • 1970-01-01
  • 2016-05-28
  • 2014-12-14
  • 2013-09-26
  • 2016-11-22
  • 2021-05-19
相关资源
最近更新 更多