从c#迁移到c++, QueryPerformanceCounter和clock会产生令人困惑的结果

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

本文关键字:结果 clock 迁移 c++ QueryPerformanceCounter      更新时间:2023-10-16

在c#中,我使用Stopwatch类。我可以得到滴答,毫秒,没有问题。

现在,我正在测试代码,而学习c++我试图得到测量,但是我不知道与c# Stopwatch解决方案等效的结果在哪里。我试着去搜索,但是信息太广泛了,我找不到一个绝对的解决方案。

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 << "rnRes Clck: " marginClck<< std::endl;

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

c#秒表的正确等效方法是什么?

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链接中的chrono方法也是基于QueryPerformanceCounter

MSDN建议使用QueryPerformanceCounter (QPC)处理高分辨率邮票:
获取高分辨率时间戳

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

对于托管代码,System.Diagnostics.Stopwatch类使用QPC作为其精确的时间基础

此函数应具有合理的精度:

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

计算机时钟通常精确到每天±1秒。

从上面的链接:

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;
}

你的bug是这样的。你有StartCounter返回CounterStart = li.QuadPart;

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

。一个被PCFreq分,另一个没有。然后用一个减去另一个是无效的。