`std::chrono`时钟和`boost::xtime`的比较

3
C ++11的std :: chrono时钟steady_clockhigh_resolution_clock在各种平台上的瑕疵和一般属性方面如何与boost :: xtime :: xtime_get()进行比较?
标准不保证high_resolution_clock是稳定的(它明确提到可能是system_clock的别名),因此需要注意这一点。其他我想到的特性有:
分辨率:C ++11标准似乎没有保证任何分辨率;这些时钟的“实际”分辨率是多少?boost :: xtime_get()在相同系统上表现如何?
最大持续时间:我知道例如clock()在具有32位clock_t和1 MHz名义时钟分辨率的系统上大约在一小时后会出故障。 (是的,我知道clock()的预期工作略有不同。)C ++11标准时钟是否能够处理几天甚至数周的持续时间,在所有已知平台上?
任何其他已知问题或令人惊讶的怪癖(编辑:无论是std :: chrono 时钟还是boost :: xtime :: xtime_get )?

1
嗯,一个明显的比较是其中一个是标准的,而另一个则不是。 - François Andrieux
2
如果您关心 high_resolution_clock 的稳定性,它有一个 is_steady 成员,如果在该平台上是稳定的,则为 true - François Andrieux
这个内容可以写成一篇不错的文章,但对于这里的回答来说太过宽泛。 - 463035818_is_not_a_number
@FrançoisAndrieux 更新了问题;我之前没有给出任何boost怪癖的例子是因为我目前不知道有哪些。 - Christoph Lipka
如果您碰巧“知道”任何此类文章,欢迎您将链接发布为答案;) - Christoph Lipka
1
如果我知道这样一篇文章,我可以总结主要观点并写出答案,但仅发布链接不被视为适当的答案,无论如何我不知道 ;) - 463035818_is_not_a_number
2个回答

4
C++11中的std::chrono时钟steady_clock和high_resolution_clock在各个平台上的特性和一般属性与boost::xtime::xtime_get()相比如何?
任何计时库都只能提供底层操作系统/硬件组合可以提供的内容,没有例外。即使库API承诺纳秒级分辨率,这也并不意味着底层操作系统/硬件可以提供该精度。因此,最终的计时API无法改善平台的质量。
boost::xtime基本上是由C标准化(随后是C ++)的timespec。这是一个{秒,纳秒}对,根据它在标准C头文件中使用的函数不同,既用作时间点,又用作时间持续时间。尽管快速调查boost头文件似乎仅将xtime用作时间点(我可能错过了某些内容)。
timespec具有长期的存在历史,在POSIX系统中特别常见。它已经存在于POSIX系统上比std::chrono更长时间,std::chrono于2008年设计,并在C ++ 11(2011)中标准化。
timespec(xtime)的范围通常大于宇宙的年龄。但是,在无法提供64位整数类型的系统上,timespec的范围将显着较小:+/- 68年,通常以1970年为中心,当它用作时间点时。
如上所述,timespec“广告”所有平台上的纳秒精度,但只能提供底层平台可以提供的精度。
chrono为时间点和持续时间提供了单独的类型。这有助于在编译时捕获错误。例如,如果将两个时间点相加,它将无法编译。今天早上9点+今天早上7点是没有意义的。但是如果减去两个时间点,则是有意义的,并返回一个单独的类型:持续时间。今天早上9点-今天早上7点是2小时。
chrono为持续时间和时间点提供了多种类型,其精度和表示形式均可能不同。 "内置"持续时间为纳秒,微秒,毫秒,秒,分钟和小时,每种都使用带符号整数类型表示(该列表在C ++20规范中扩展)。但是,您可以创建自己的持续时间类型,具有自己的精度和表示形式(例如,浮点或安全int库)。
实现任何给定平台的chrono实现者都可以宣传平台"now()"函数的精度。即,它不必总是纳秒,可以是微秒或其他单位。厂商没有义务诚实,但他们通常会这样做。客户端可以在编译时以编程方式查询now()的返回类型及其精度(毕竟这是C++)。 chrono数据结构是{单位计数},而不是xtime{秒、纳秒}数据结构。对于chrono,即使这些是不同的类型,这也适用于持续时间和时间点。 {单位计数}布局相比{秒、纳秒}布局具有几个优点:
  • 有机会拥有更小的sizeofsystem_clock::time_point通常为64位,而xtime通常为128位。这确实使xtime具有卓越的范围。但是,chrono库还可以与128位积分类型一起使用,随后将具有比xtime更大的范围。
  • 客户端可以通过chrono进行大小/范围权衡。 xtime客户端将得到他们的内容。
  • 使用{计数}数据结构进行算术运算更快、更高效,编程也更容易,而使用{秒、纳秒}则会导致代码更小、更快,并且通常更少出现错误(使用{秒、纳秒}表示负值是一个长期的恐怖故事)。
  • 对于给定的sizeof和精度,可以始终使用{count}数据结构获得比多字段数据结构(如{seconds, nanoseconds})具有更大范围的结果。

标准不保证high_resolution_clock稳定(它明确提到可能是system_clock的别名),因此这是需要注意的一个陷阱。

实际上,high_resolution_clock总是类型别名,可用于steady_clocksystem_clock。这取决于平台。我的建议是直接使用steady_clocksystem_clock,以便您知道正在处理什么。

分辨率:C++11标准似乎未保证任何分辨率;这些时钟的“现实生活”分辨率是什么?

宣传的分辨率是:
libc++/llvm:

system_clock
    rep is long long : 64 bits
    period is 1/1,000,000
    is_steady is 0

high_resolution_clock
    rep is long long : 64 bits
    period is 1/1,000,000,000
    is_steady is 1

steady_clock
    rep is long long : 64 bits
    period is 1/1,000,000,000
    is_steady is 1

high_resolution_clock is the same type as steady_clock

libstdc++/gcc:

system_clock
    rep is long : 64 bits
    period is 1/1,000,000,000
    is_steady is 0

high_resolution_clock
    rep is long : 64 bits
    period is 1/1,000,000,000
    is_steady is 0

steady_clock
    rep is long : 64 bits
    period is 1/1,000,000,000
    is_steady is 1

high_resolution_clock is the same type as system_clock

VS-2013:

system_clock
    rep is __int64 : 64 bits
    period is 1/10,000,000
    is_steady is 0

high_resolution_clock
    rep is __int64 : 64 bits
    period is 1/1,000,000,000
    is_steady is 1

steady_clock
    rep is __int64 : 64 bits
    period is 1/1,000,000,000
    is_steady is 1

high_resolution_clock is the same type as steady_clock

由于我开场白的原因,"现实生活"中的解决方案很可能与任何给定平台上的相同。
C++11标准时钟是否能在所有已知平台上处理以天、甚至是周为单位的持续时间?
可以。即使是月份和年份也可以。
你会遇到的第一个持续时间限制是处理纳秒分辨率时。chrono保证它将具有至少64位有符号整数表示,使您拥有+-292年的范围。当涉及system_clock时,该范围将以1970年为中心。
还有其他已知的问题或令人惊讶的怪癖吗?
当操作接近或超过范围限制时,chrono库很容易且无声地溢出。例如,如果将microseconds::max()与nanoseconds::max()进行比较,则会发生溢出并获得不确定的结果。这是因为比较运算符将在执行比较之前先将微秒转换为纳秒,并且该转换会导致溢出。
尽量避开持续时间和time_point范围限制。如果不得不处理它们,并且不确定如何处理,请在Stackoverflow上寻找答案。如果搜索结果不令人满意,请提出特定于您关注的问题。

哇,感谢你提供如此详细的答案。- 所以,如果我需要测量代码片段经过的墙上时钟时间,精度在毫秒级别,但代码有时可能运行数周甚至更长时间,那么就实际而言,“std::chrono::steady_clock”将是符合标准且可移植的最佳选择? - Christoph Lipka
steady_clock 是毫秒级别计时的好选择。但对于几周的计时来说,它不是很好。但也不是太糟糕。steady_clock 通常会计算您平台的硬件时钟周期计数器,并将其转换为方便的单位,如纳秒。但没有完美的时钟,您计算机的时钟处于平均水平较低的一面。您的石英手表通常每周会慢一两秒。您计算机的时钟不会更好,甚至可能更差。 - Howard Hinnant
1
system_clock 将定期向网络上的其他时钟询问时间并进行自我校正。因此,在毫秒级别的短时间间隔计时方面效果较差,但在长达数周的时间间隔计时方面效果更佳。 steady_clocksystem_clock 均可使用。但各有其优点和缺点。 - Howard Hinnant

0

测试使用持续时间为1毫秒的sleep_for的一些第一手和第二手结果:

以下平台通常会“睡眠过度”,至少平均计时超过1000次迭代:

  • Windows子系统用于Linux / g++(1.8毫秒,显然是开销)
  • 正版Ubuntu / g++(1.1毫秒)
  • FreeBSD / clang(1.1毫秒)
  • Wingwin / g++(16毫秒,显然是最小值)
  • OS X(Darwin)/ g++ / POSIX线程模型(1.2毫秒)

到目前为止,没有平台平均“睡眠不足”。


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