2015-12-14 79 views
2

我记录时间戳在我的程序与下面的代码块:一致时间戳与标准::计时

// Taken at relevant time 
m.timestamp = std::chrono::high_resolution_clock::now().time_since_epoch(); 


// After work is done 
std::size_t secs = std::chrono::duration_cast <std::chrono::seconds> (timestamp).count(); 
std::size_t nanos = std::chrono::duration_cast<std::chrono::nanoseconds> (timestamp).count() % 1000000000; 
std::time_t tp = (std::time_t) secs; 

std::string mode; 
char ts[] = "yyyymmdd HH:MM:SS"; 
char format[] = "%Y%m%d %H:%M:%S"; 
strftime(ts, 80, format, std::localtime(&tp)); 

std::stringstream s; 
s << ts << "." << std::setfill('0') << std::setw(9) << nanos 
    << " - " << message << std::endl; 
return s.str(); 

我比较这些由一个精确的远程源记录时间戳。当时间戳的差异被绘制并且ntp没有被启用时,整天都有一个线性漂移(每30秒左右700微秒)。

graph1

校正线性漂移后,我发现有一个非线性元件。它可以在几个小时内进出数百微秒。

graph2

第二幅图看起来类似于如上相同的方法拍摄的图形,但启用NTP。数据中预计会出现大的垂直尖峰,但最小的摆动是令人惊讶的。

有没有办法获得更精确的时间戳,但保留微秒/纳秒分辨率?如果时钟以可预测的方式从实际时间漂移,那么可以,但时间戳在长时间内需要内部一致。

+1

这不是一个真正的C++问题,因为std :: chrono函数只是从您的操作系统/硬件中获取时间。它似乎更可能是关于你的硬件。 –

+1

上次我查看C++(特别是微软)支持的“高分辨率定时器”是“iffy”这个Q/A http://stackoverflow.com/questions/26003413/stdchrono-or-boostchrono-support-for-clock-尽管我试图实现不同的目标,但单调 - 粗糙可能是有趣的。 –

回答

3

high_resolution_clock与“当前时间”没有保证关系。您的系统可能没有别名high_resolution_clocksystem_clock。这意味着你可以或不会以这种方式使用high_resolution_clock。使用system_clock。然后告诉我们情况是否改变(可能不会)。

此外,更好的作风:

using namespace std::chrono; 
auto timestamp = ... // however, as long as it is based on system_clock 
auto secs = duration_cast <seconds> (timestamp); 
timestamp -= secs; 
auto nanos = duration_cast<nanoseconds> (timestamp); 
std::time_t tp = system_clock::to_time_t(system_clock::time_point{secs}); 
  • 留在计时类型系统尽可能长。
  • 使用计时类型系统为您进行转换和算术。使用system_clock::to_time_t转换为time_t

但最终,以上都不会改变您的任何结果。 system_clock只是要与操作系统交谈(例如拨打gettimeofday或其他)。

如果您可以设计一种更准确的方法来确定系统的时间,可以将该解决方案包装在“计时兼容时钟”中,以便继续使用计时的类型安全性和转换因子持续时间和时间点。

struct my_super_accurate_clock 
{ 
    using rep  = long long; 
    using period  = std::nano; // or whatever? 
    using duration = std::chrono::duration<rep, period>; 
    using time_point = std::chrono::time_point<my_super_accurate_clock>; 

    static const bool is_steady = false; 

    static time_point now(); // do super accurate magic here 
}; 
+0

我认为high_resolution_clock对于我来说(运行CentOS Linux)是别名system_clock。将时钟更改为system_clock将生成具有相同分辨率的时间戳。需要一些时间来衡量一天内的漂移。 – user2411693

+0

好吧,gcc的实现已知将'high_resolution_clock'别名为'system_clock'。所以纠正这一点不会改变你的任何东西,除了让你的代码更加便携。 –

+0

感谢您的清理版本。是的,我认为VS做了同样的别名。但是,如果我正确理解文档,则在使用steady_clock(没有转换为挂钟时间)的系统上,对time_t的转换将是无稽之谈。我很惊讶,我得到了系统时钟的纳秒分辨率。 – user2411693

1

的问题是,除非你的机器是非常不寻常的,底层的硬件根本不是提供的时间特别可靠的测量能够(至少放在秤上,你正在寻找)。

无论是在数字手表还是工作站上,大多数电子时钟信号都由crystal oscillator在内部生成。这种晶体在其“理想”频率附近具有长(年)和短期(分钟)变化,最大短期成分随温度变化。花式实验室设备将具有类似于crystal oven这样的设备,它试图将晶体保持在恒定的温度(高于环境温度)以最小化与温度有关的漂移,但是我从未在商品计算硬件上看到类似的情况。

您可以在两个图形中以不同方式看到晶体不准确性的影响。第一张图简单地表明,由于制造过程中的变化(总是那么糟糕)或者长期漂移(随着时间的推移而变化),你的晶体与真实时间的偏差有点大。一旦启用了NTP,“常量”或平均偏差从真正被轻易纠正,因此您可以期望在一段较长的时间内实现零偏移(实际上该线由最小降低到零和低于零)。

然而,在这种规模下,您会看到较小的短期变化。 NTP会周期性地启动并试图“修复它们”,但短期漂移始终存在并始终在变化方向(甚至可能检查增加或降低环境温度的效果并在图中看到它)。

您无法避免摆动,但您可以增加NTP调整频率,以使其更紧密地与实时耦合。您的具体要求并不完全清楚。比如你提到:

这没关系,如果时钟与实际时间以可预见的方式 漂移,但时间戳将需要内部一致在 长的时间段。

“内部一致”是什么意思?如果您可以随意使用漂移,只需使用您的现有时钟即可,无需NTP调整。如果你想要像“时间跨度很长”的实时追踪时间(即,它不会得到也不同步),为什么可以使用内部时钟并结合定期轮询“外部源”并以平稳的方式更改调整系数,以便在明显时间内不会出现“跳跃”。这基本上重塑了NTP,但至少它将完全处于应用程序控制之下。