使用C++11正确地实现代码的可移植计时方式

8
我正在编写一些计时代码,用于程序中具有低延迟要求的部分。
查看std :: chrono库中可用的内容,我发现编写可移植的计时代码有点困难。
以下是三个可用的时钟:
1. std :: chrono :: high_resolution_clock 2. std :: chrono :: steady_clock 3. std :: chrono :: system_clock
system_clock无用,因为它不稳定;剩下的两个时钟存在问题。
high_resolution_clock在所有平台上都不一定稳定。
steady_clock不一定支持细粒度分辨率时间段(例如:纳秒)。
对于我的目的,拥有一个稳定的时钟是最重要的要求,我可以通过微秒粒度来满足这个需求。
我的问题是,如果想计时可能在不同硬件架构和操作系统上运行的代码,什么选项最好?

4
在你绝对不能后退的时候,你需要稳定。偶尔出现的虚假的后向剖析数值......那会导致伤亡吗? - Yakk - Adam Nevraumont
@Yakk,对于向前跳跃,例如由NTP引起的时间更改,也是如此吗? - Lucinda Rigetti
2
当然。但你正在进行性能分析,而不是移动资金或控制喷气发动机。一些噪音可以预料到,仅仅是由于上下文切换等原因;它不稳定的重点在于有时保证稳定是昂贵的,除非你需要这种保证,否则为其付费是不值得的。 - Yakk - Adam Nevraumont
当你说“高分辨率点击在所有平台上都不稳定”时,你是什么意思? - Dai
1
@Dai:OP的意思是high_resolution_clock不是“稳定的”,即它不是单调的。 - John Zwinck
@JohnZwinck 没错! - Lucinda Rigetti
1个回答

6
使用steady_clock。在所有实现中,其精度为纳秒。您可以通过打印steady_clock::period::numsteady_clock::period::den来检查您的平台是否符合此要求。
但这并不意味着它实际上会测量纳秒精度。但各个平台都尽力而为。对我来说,启用优化后调用两次steady_clock将报告大约相差100ns的时间。
#include "chrono_io.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    using namespace date;
    auto t0 = steady_clock::now();
    auto t1 = steady_clock::now();
    auto t2 = steady_clock::now();
    auto t3 = steady_clock::now();
    std::cout << t1-t0 << '\n';
    std::cout << t2-t1 << '\n';
    std::cout << t3-t2 << '\n';
}

上面的例子仅为方便格式化持续时间而使用此免费,开源,仅头文件库。您可以自己格式化内容(我很懒)。对我来说,这只是输出:
287ns
116ns
75ns

因人而异。


1
非常棒的回答!谢谢你。但有一个小问题,既然steady_clock可以在纳秒级别工作,那么高精度时钟(high_resolution_clock)的用途是什么?在使用steady_clock的情况下,为什么还需要高精度时钟? - Lucinda Rigetti
对于Windows,steady_clock是高性能计数器。对于Windows XP,它通常以CPU时钟速率运行,如3.5 GHz。对于Windows 7及更高版本,它通常以CPU时钟速率的1/1000左右运行,例如3.5 MHz。我不知道Windows Vista的情况。 - rcgldr
1
@rcgldr:VS std::lib团队多年来一直在处理<chrono>的问题并进行改进。如果你被卡在一个无法使用<chrono>的版本上,可以编写自己的定制chrono时钟,直接与操作系统或硬件连接。有SO答案解释如何实现。 - Howard Hinnant
1
@HowardHinnant 那是另一个优秀的SO帖子!谢谢。 - Lucinda Rigetti
相关:精确时间测量有一个使用QueryPerformanceCounter的Windows答案,那里的评论说VS14终于有了一个好的std::chrono::high_resolution_clock - Peter Cordes
请注意,CPU 频率可能会有所变化,因此在微基准测试中测量挂钟时间并不总是最有用的,除非您禁用 Turbo 和省电模式。或者至少先热身你的基准测试。如果您不想这样做,HW 性能计数器可以为您提供核心时钟周期,但这取决于操作系统和硬件。(参见 std::chrono::clock、硬件时钟和周期计数) - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接