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

时间:2015-10-21 14:09:26

标签: c++ windows winapi timing

在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 << "\r\nRes Clck: " marginClck<< std::endl;

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

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

2 个答案:

答案 0 :(得分:1)

你的错误就是这个。您StartCounter返回CounterStart = li.QuadPart;

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

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

答案 1 :(得分:1)

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,它基于计算机启动的时间。当您执行Stop-Watch类型减法时,结果非常接近。 QueryPerformanceCounter更准确。来自@ BoPersson链接的chrono方法也基于QueryPerformanceCounter

MSDN建议将QueryPerformanceCounter(QPC)用于高分辨率标记:
Acquiring high-resolution time stamps

在托管代码中使用相同的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;
}