5

我试图用来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);
}

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

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

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

这是一个 Windows 程序。

4

2 回答 2

10

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

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

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

std::cout << "seconds since start: " << ((double) difference / 1000000);

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

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

我想以双精度表示的秒数来查看输出。

然后你应该chrono为你做那个。一旦你学会了如何做就很容易了:

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

第一行创建一个周期为 1 秒的类型,用双精度表示。

第二行只是减去您的 time_points 并将其分配给您的自定义持续时间类型。库自动完成从单位steady_clock::time_point到自定义持续时间(双秒)的转换。chrono这比:

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

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

std::cout << "seconds since start: " << ((double) difference / 1000000);


但是由于您对 的精度不满意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;
    }
};

由于您希望输出以双秒为单位,因此我将rep这个时钟设为 adoubleperiod1 秒。您可以轻松地制作rep积分和period其他一些单位,例如微秒或纳秒。您只需调整typedefs 和从QueryPerformanceCounterdurationin的转换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';
}

但是没有手动编码的转换常数,并且我希望)有足够的精度来满足您的需求。并且为未来的实现提供了更容易的移植路径。std::chrono::steady_clock

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

于 2013-04-02T04:04:36.617 回答
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;
}   
于 2013-04-01T22:12:22.213 回答