QueryPerformanceCounter 抛出不正确的数字

Posted

技术标签:

【中文标题】QueryPerformanceCounter 抛出不正确的数字【英文标题】:QueryPerformanceCounter throwing incorrect numbers 【发布时间】:2014-08-13 00:51:26 【问题描述】:

我正在使用 QueryPerformanceCounter 来测量某些功能/操作的时间。它曾经给我正确的数字,例如,我可以测试 Sleep(1000),它会返回一个非常接近 1 秒的时间。现在,它返回一个非常不同的时间。我不确定问题是什么,因为代码根本没有改变。代码如下:

预期输出:

duration : 1.000 seconds

实际输出:

duration : 187.988 seconds

代码:

#include <windows.h>
#pragma comment (lib, "winmm.lib")


struct Clock

Clock()
virtual ~Clock()
void start();
void stop();
long double duration();

LARGE_INTEGER _start, _end, _freq;

;

void Clock::start()
_start.QuadPart = 0;
QueryPerformanceCounter(&_freq);
QueryPerformanceCounter(&_start);


void Clock::stop()
QueryPerformanceCounter(&_end);


long double Clock::duration()
//microseconds
LARGE_INTEGER delta;
delta.QuadPart = (_end.QuadPart - _start.QuadPart) * 1000000;
long double the_duration = ((long double)delta.QuadPart) / _freq.QuadPart;
std::cout << "duration : " << the_duration << " seconds" << std::endl;
return the_duration;






void main()

Clock clock;

clock.start();
Sleep(1000);
clock.stop();
clock.duration();

std::cin.get();

【问题讨论】:

一个永恒的时间问题 - viva64.com/en/b/0097 【参考方案1】:

您假设性能计数器的频率正好是 1000000 Hz。

您需要改为调用QueryPerformanceFrequency,因为频率可能会有所不同(一些内核使用主板的 1.024 MHz 定时器,其他内核使用 CPU 时间戳计数器,它以大约 CPU 的时钟频率运行)。

【讨论】:

另外请记住,QPC 在现代硬件中的用处不如过去。众所周知,它不适用于现代多核 CPU 或动态限制 CPU 频率的现代 Windows 版本(尽管MSDN says)。是的,QPC “有效”,但有时您可能会得到不同/不正确的结果。 感谢 Remy - 我现在使用 QueryPerformanceFrequency(&amp;_freq) 并摆脱了 *1000000 并且结果返回 1.00007 seconds. 如果 QPC/QPF 不是最好的,你会推荐什么?您能否指导我阅读有关此板上的一些文献或讨论,以了解更好的替代方案? @RemyLebeau:是的——虽然这很不寻常,但有时我什至设法得到一个早于开始时间的结束时间。 @JerryCoffin:小心,在没有暂停或动态 CPU 速度调整的情况下,直接使用 RDTSCP 可能会更好,但您必须将线程关联设置为单个内核或在比较跨核样本时进行一些跨核校准并接受错误窗口。 @Chewco:在我的测试中,QPC 经常依赖 RDTSC,并且在不同内核上采集样本时无法可靠工作,因此问题在于系统负载迫使线程跨内核移动,以及内核之间 TSC 寄存器的不同步,MS 说 HAL(Bios 中的硬件抽象层)负责 - 这不是一个很有帮助的位置。 (MS声称这在Win7下有所改进,但我不相信)。【参考方案2】:

我在 VBA 中使用它。有时我得到 8976543566 毫秒而不是 40 我通过在程序开始时调用它两次来处理它:

如果 gbolShowRunTime = True 那么

QueryPerformanceCounter curFrequencyStartLoop

如果结束

如果 gbolShowBFTime = True 那么

QueryPerformanceCounter curFrequencyEndLoop '获取结束时间

QueryPerformanceCounter curFrequencyStartLoop ' 重新播种

如果结束

之后就可以正常使用了。

【讨论】:

正如其他答案所述,单独调用QueryPerformanceCounter() 是不够的,您还需要调用QueryPerformanceFrequency()

以上是关于QueryPerformanceCounter 抛出不正确的数字的主要内容,如果未能解决你的问题,请参考以下文章

QueryPerformanceCounter 运行时错误

为啥与两者相比得到不同的毫秒值(QTIme 和 QueryPerformanceCounter)

QueryPerformanceCounter 是不是保证在启动后给您时间?

QueryPerformanceCounter 抛出不正确的数字

QueryPerformanceCounter 和奇怪的结果

QueryPerformanceCounter 状态?