测量时间导致返回值为0或0.001

rap*_*yen 5 c++ windows time c++11 c++-chrono

我试图用来chrono::steady_clock衡量程序中代码块之间经过的小数秒.我在LiveWorkSpace(http://liveworkspace.org/code/YT1I$9)中使用了这段代码:

#include <chrono>
#include <iostream>
#include <vector>

int main()
{
    auto start = std::chrono::steady_clock::now();
    for (unsigned long long int i = 0; i < 10000; ++i) {
       std::vector<int> v(i, 1);
    }
    auto end = std::chrono::steady_clock::now();

    auto difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();

    std::cout << "seconds since start: " << ((double)difference / 1000000);
}
Run Code Online (Sandbox Code Playgroud)

当我在我的程序中实现相同的想法时:

auto start = std::chrono::steady_clock::now();
// block of code to time
auto end = std::chrono::stead_clock::now();

auto difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()

std::cout << "seconds since start: " << ((double) difference / 1000000);
Run Code Online (Sandbox Code Playgroud)

该程序将只打印0和的值0.001.我非常怀疑我的代码块的执行时间总是等于01000微秒,那么这个舍入的原因是什么,以及如何消除它以便我可以获得正确的小数值?

这是一个Windows程序.

How*_*ant 6

这个问题已经有了一个很好的答案.但我想补充一点建议:

<chrono>框架内工作.建立自己的时钟.建立自己的time_point.建立自己的持续时间.该<chrono>框架非常可定制.通过在该系统中工作,您不仅可以学习std::chrono,而且当您的供应商开始提供您满意的时钟时,将您的代码从手动滚动的时间转换为std::high_resolution_clock(或其他)将是微不足道的.

首先,对您原始代码的一点点批评:

std::cout << "seconds since start: " << ((double) difference / 1000000);
Run Code Online (Sandbox Code Playgroud)

每当你看到自己引入转换常量(如1000000)来获得你想要的东西时,你就没有chrono正确使用它.你的代码不正确,只是脆弱.你确定你在那个常数中得到了正确数量的零吗?!

即使在这个简单的例子中,你应该对自己说:

我希望以双精度表示的秒数来看输出.

然后你应该chrono为你做这件事.一旦你学会了如何,这很容易:

typedef std::chrono::duration<double> sec;
sec difference = end - start;
std::cout << "seconds since start: " << difference.count() << '\n';
Run Code Online (Sandbox Code Playgroud)

第一行创建一个周期为1秒的类型,由double表示.

第二行只是减去你的time_points并将其分配给你的自定义持续时间类型.从单位steady_clock::time_point到自定义持续时间(两秒)的转换由chrono库自动完成.这比以下简单得多:

auto difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()
Run Code Online (Sandbox Code Playgroud)

最后,您只需使用.count()成员函数打印出结果.这又比以下简单得多:

std::cout << "seconds since start: " << ((double) difference / 1000000);
Run Code Online (Sandbox Code Playgroud)

但是,由于您对精确度不满意std::chrono::steady_clock,并且您可以访问QueryPerformanceCounter,因此您可以做得更好.您可以在QueryPerformanceCounter之上构建自己的时钟.

<disclaimer>

我没有Windows系统来测试以下代码.

</disclaimer>

struct my_clock
{
    typedef double                             rep;
    typedef std::ratio<1>                      period;
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<my_clock>  time_point;
    static const bool is_steady =              false;

    static time_point now()
    {
        static const long long frequency = init_frequency();
        long long t;
        QueryPerformanceCounter(&t);
        return time_point(duration(static_cast<rep>(t)/frequency));
    }
private:
    static long long init_frequency()
    {
        long long f;
        QueryPerformanceFrequency(&f);
        return f;
    }
};
Run Code Online (Sandbox Code Playgroud)

既然你想要你的输出以两秒钟的速度表示,我已经把rep这个时钟变为a doubleperiod1秒.您可以轻松地制作rep积分和period其他一些单位,如微秒或纳秒.您只需将typedefs和转换调整QueryPerformanceCounter为您的durationin now().

现在您的代码看起来很像原始代码:

int main()
{
    auto start = my_clock::now();
    for (unsigned long long int i = 0; i < 10000; ++i) {
       std::vector<int> v(i, 1);
    }
    auto end = my_clock::now();

    auto difference = end - start;
    std::cout << "seconds since start: " << difference.count() << '\n';
}
Run Code Online (Sandbox Code Playgroud)

但是,没有手工编码的转换系数,并(就是我希望是)足够的精度满足您的需求.并且有一个更容易的移植路径到未来的std::chrono::steady_clock实现.

<chrono>被设计成一个可扩展的库.请延长它.:-)


Jes*_*ood 2

在 MSVC2012 上运行一些测试后,我可以确认 Microsoft 实现中的 C++11 时钟没有足够高的分辨率。有关此问题的错误报告,请参阅C++ 标头的 high_resolution_clock 没有高分辨率。

因此,不幸的是,对于更高分辨率的计时器,您将需要boost::chrono像这样直接使用 QueryPerformanceCounter ,直到他们修复错误:

#include <iostream>
#include <Windows.h>

int main()
{
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);

    LARGE_INTEGER start;
    QueryPerformanceCounter(&start);

    // Put code here to time

    LARGE_INTEGER end;
    QueryPerformanceCounter(&end);

    // for microseconds use 1000000.0
    double interval = static_cast<double>(end.QuadPart- start.QuadPart) / 
                      frequency.QuadPart; // in seconds
    std::cout << interval;
}   
Run Code Online (Sandbox Code Playgroud)