从 C# 迁移到 C++,QueryPerformanceCounter 与时钟产生令人困惑的结果

Moving from C# to C++, QueryPerformanceCounter vs clock produce confusing results

在 C# 中,我使用 Stopwatch class。我可以毫无问题地获取滴答声和毫秒数。

现在我在学习 C++ 的同时测试代码,我尝试进行测量,但是 我不知道匹配 C# 秒表解决方案的等效结果在哪里。我试图搜索,但信息太广泛,我找不到绝对的解决方案。

double PCFreq = 0.0;
__int64 CounterStart = 0;
void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
    std::cout << "QueryPerformanceFrequency failed!\n";
    PCFreq = double(li.QuadPart)/1000.0;
    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}

double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}

因为这给了我两个不同的结果,所以我倾向于相信时钟。 :)

start =  StartCounter()
//some function or for loop
end = GetCounter()
marginPc = end - start;

start = clock();
// ...same
end= clock();
marginClck = end - start;

std::cout<< "Res Pc: " << marginPc << "\r\nRes Clck: " marginClck<< std::endl;

对于时钟版本,我尝试了 unsigned intdouble,但结果仍然不同。

相当于 C# 秒表的正确方法是什么?

你的错误是这个。你有 StartCounter return CounterStart = li.QuadPart;

但是GetCounter returns double(li.QuadPart-CounterStart)/PCFreq.

即一个除以 PCFreq 而另一个不除。然后从另一个中减去一个是无效的。

clock() 给出程序启动后的毫秒数。例如,下面的程序将打印一个接近 500 的数字:

int main()
{
    Sleep(500);
    cout << clock() << endl;

    /*
    POSIX version:
    std::cout << clock() * 1000.0 / CLOCKS_PER_SEC << std::endl;
    CLOCKS_PER_SEC is 1000 in Windows
    */

    return 0;
}

QueryPerformanceCounter有点类似于GetTickCount64,它是根据计算机启动的时间来计算的。当你做秒表类型的减法时,结果非常接近。 QueryPerformanceCounter 更准确。来自@BoPersson 的 link 的 chrono 方法也基于 QueryPerformanceCounter.

MSDN 建议对高分辨率图章使用 QueryPerformanceCounter (QPC):
Acquiring high-resolution time stamps

托管代码中使用了相同的 QPC 函数:

For managed code, the System.Diagnostics.Stopwatch class uses QPC as its precise time basis

这个函数应该有合理的精度:

long long getmicroseconds()
{
    LARGE_INTEGER fq, t;
    QueryPerformanceFrequency(&fq);
    QueryPerformanceCounter(&t);
    return 1000000 * t.QuadPart / fq.QuadPart;
}

计算机时钟通常每天精确到 +/-1 秒。

自上而下link:

Duration          Uncertainty
1 microsecond     ± 10 picoseconds (10-12)
1 millisecond     ± 10 nanoseconds (10-9)
1 second          ± 10 microseconds
1 hour            ± 60 microseconds
1 day             ± 0.86 seconds
1 week            ± 6.08 seconds

为了简化您的其他函数,您可以避免 double 结果。 QuadPartlong long,因此在整个函数中使用它:

long long PCFreq = 0;
long long CounterStart = 0;
void StartCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceFrequency(&li);
    PCFreq = li.QuadPart;
    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}

long long GetCounter()
{
    if (PCFreq < 1) return 0;
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);

    //for milliseconds: 1,000
    return  1000 * (li.QuadPart - CounterStart) / PCFreq;

    //for microseconds: 1,000,000
    //return  1000000 * (li.QuadPart - CounterStart) / PCFreq;
}