我正在尝试使用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
值。 我非常怀疑我的代码块的执行时间总是等于0
或1000
微秒,那么这个四舍五入的计算是什么,我怎样才能消除它,以便我可以得到正确的小数值?
这是一个Windows程序。
在MSVC2012上运行一些测试之后,我可以确认微软实施的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; }
这个问题已经有了很好的答案。 但我想补充一点建议:
在<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
单位到自定义持续时间( steady_clock::time_point
的转换由steady_clock::time_point
库自动完成。 这比以下简单得多:
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
的精度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
double
了1秒。 你可以很容易地做出rep
积分和其他单位,如微秒或纳秒。 您只需在now()
调整typedef
和从QueryPerformanceCounter
到您的duration
的转换即可。
现在你的代码看起来很像你的原始代码:
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>
被设计成一个可扩展的库。 请扩展它。 🙂