![](/img/trans.png)
[英]create std::tuple using compile-time types and a run-time function
[英]extending the std::chrono functionality to deal with run-time (non compile-time) constant periods
我一直在Linux和OSX上尝试各种计时器,并且想尝试使用std :: chrono使用的相同接口来包装它们中的一些。
对于在编译时具有明确定义的“周期”的定时器,例如POSIX clock_gettime()familiy,OSX上的clock_get_time()系列或gettimeofday(),这很容易做到。
但是,有一些有用的计时器,“周期” - 而常量 - 只在运行时才知道。 例如: - POSIX表示clock()的周期,CLOCKS_PER_SEC,可能是非XSI系统上的变量 - 在Linux上,时间段()由运行时由sysconf(_SC_CLK_TCK)给出 - 在OSX上, mach_absolute_time()在运行时由mach_timebase_info()给出 - 在最近的英特尔处理器上,DST寄存器以恒定速率滴答,但当然只能在运行时确定
要将这些计时器包装在std :: chrono接口中,一种可能性是使用一段std :: chrono :: nanosecond,并将每个计时器的值转换为纳秒。 另一种方法可以是使用浮点表示。 但是,这两种方法都会给now()函数带来(非常小的)开销,并且精度会损失(可能很小)。
我试图解决的解决方案是定义一组类来表示这样的“运行时常量”周期,这些周期与std :: ratio类相同。 但是我希望这将需要重写所有相关的模板类和函数(因为它们假设constexpr值)。
我如何将这些计时器包装成一个标准:chrono?
或者在时钟的时间段内使用非constexpr值?
有没有人有任何经验来包装这些计时器:chron?
其实我这样做。 在OSX上,您感兴趣的平台之一。 :-)
你提到:
在OSX上,mach_absolute_time()的周期在运行时由mach_timebase_info()给出
完全正确。 同样在OSX,在libc中++的执行high_resolution_clock
和steady_clock
实际上是基于mach_absolute_time
。 我是这段代码的作者,这是一个开源的慷慨许可证(只要您保留版权,就可以随意做任何事情)。
这是libc ++的steady_clock::now()
的源代码。 它的构建方式与您推测的方式非常相似。 运行时间段在返回之前转换为纳秒。 在OS X上,转换因子通常为1,并且代码通过优化利用了这一事实。 但是,代码通常足以处理非1转换因子。
在第一次调用now()
,查询运行时转换因子为纳秒的成本很低。 在一般情况下,计算浮点转换因子。 在通常情况下(转换因子== 1),后续成本是通过函数指针调用。 我发现开销真的很合理。
在OS X上,转换因子虽然直到运行时才确定,但仍然是一个常量(即不随程序执行而变化),因此它只需要计算一次。
如果您的周期实际上是动态变化的,那么您需要更多的基础设施来处理这个问题。 基本上,您需要整合(微积分)周期与时间曲线,然后计算两个时间点之间的平均周期。 这需要随着时间的推移不断监测周期, <chrono>
不是正确的工具。 这些工具通常在OS级别处理。
我为自己的目的做了类似的事情,但仅限于Linux。 你在这里找到代码; 随时以您想要的方式使用代码。
我的实现所遇到的挑战与您问题中提到的问题部分重叠。 特别:
在运行时检索滴答因子(从时钟滴答转换为基于秒的时间单位所需),但仅使用第一次now()
‡ 。 如果您担心这会导致较小的开销,您可以在启动之前调用now()
函数,然后再测量任何实际间隔。 tick因子存储在一个静态变量中,这意味着仍有一些开销 - 在最低级别 - now()
函数的每次调用都意味着检查静态变量是否已经初始化。 但是,这个开销在now()
每次调用中都是相同的 ,所以它不应该影响测量时间间隔。
我默认情况下不会转换为纳秒,因为在测量相对较长的时间段(例如几秒钟)时,这会导致溢出很快。 这实际上是我不使用boost实现的主要原因。 我将基本单元实现为模板参数(在代码中称为Precision
),而不是转换为纳秒。 我使用来自C ++ 11的std::ratio
作为模板参数。 所以我可以选择,例如,一个clock<micro>
,这意味着调用now()
函数将在内部转换为微秒而不是纳秒,这意味着我可以测量许多秒或分钟的周期而没有溢出,仍然具有良好的精度。 (这与用于产生输出的单位无关。您可以使用clock<micro>
并在几秒钟内显示结果等)
我的时钟类型叫做combined_clock
,它combined_clock
了用户时间,系统时间和挂钟时间。 还有一种增强时钟类型,但它与std
的比率类型和单位不兼容,而我的是。
‡使用您建议的::sysconf()
调用检索滴答因子,并保证在整个生命周期内返回一个相同的值。
所以你使用它的方式如下:
#include "util/proctime.hpp"
#include <ratio>
#include <chrono>
#include <thread>
#include <utility>
#include <iostream>
int main()
{
using std::chrono::duration_cast;
using millisec = std::chrono::milliseconds;
using clock_type = rlxutil::combined_clock<std::micro>;
auto tp1 = clock_type::now();
/* Perform some random calculations. */
unsigned long step1 = 1;
unsigned long step2 = 1;
for (int i = 0 ; i < 50000000 ; ++i) {
unsigned long step3 = step1 + step2;
std::swap(step1,step2);
std::swap(step2,step3);
}
/* Sleep for a while (this adds to real time, but not CPU time). */
std::this_thread::sleep_for(millisec(1000));
auto tp2 = clock_type::now();
std::cout << "Elapsed time: "
<< duration_cast<millisec>(tp2 - tp1)
<< std::endl;
return 0;
}
上面的用法涉及一个漂亮的打印函数,生成如下输出:
Elapsed time: [user 40, system 0, real 1070 millisec]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.