我的情况是在对我们的系统进行分析和分析之后,得出的结论是系统的记录组件是许多瓶颈之一占据总运行时间的约17% - 很多记录的东西。
其中,记录器消耗的大约5%的时间与以下格式在ascii中生成日期/时间戳相关:YYYYMMDD HHMMSS.fff - 我们大致记录每秒约700k行。 (大约700K x(localtime和gettimeofday)每秒呼叫)
我想知道有多少技术人员可以有效地制作时间戳。
欢迎跨平台解决方案。
注1:我们查看了Boost.datetime - 它很棒,但对我们的需求来说有点太慢了,std :: chrono是一个完美的解决方案,但遗憾的是我们必须支持pre c ++ 11编译器。
注意2:我们实现了一个简单的优化,它只计算每24小时一个日期部分(yyyymmdd),因此每行只有1个gettimeofday调用 - 虽然没有多大帮助。
答案 0 :(得分:3)
如果您可以选择使用C ++ 11,则应该查看std::chrono。
如果失败,优化将取决于您需要的分辨率。 我会问你是否绝对需要时间戳记日志,或者是否有序列信息的偶然时间戳可能有用?
示例:
<timestamp1> <seq_num_0> ...
<timestamp1> <seq_num_1> ...
....
<timestamp1> <seq_num_n-1> ...
<timestamp2> <seq_num_0> ...
我看到它的方式,你有两个问题:
我会使用基于计时器的系统每毫秒更新时间戳两次,并在更新之间重新使用它。然后我会确保运行代码的系统将其时钟与原子钟同步。您生成时间戳两次,以尝试并补偿底层操作系统的计时器机制的瑕疵。
我认为你不会比那更好。
编辑:实际上,你可以。确保只在更改时格式化时间戳字符串。如果您可以保证条目按照它们的顺序记录,那么您也不需要序列号。鉴于这两个假设,您的日志记录问题现在降低到连接和写出两个字符串的速度。更新2:如果BOOST不适合,如果你不能使用C ++ 11,那么归结为:
假设I / O不是你的瓶颈,那么你的问题就是快速字符串连接。
答案 1 :(得分:0)
我会延迟任何和所有格式化,直到实际需要:
struct log_entry {
struct timeval timestamp;
unsigned int code;
union {
struct param1 p1;
struct param2 p2;
};
};
paramN
结构包含适合于当时所处形式的事件的数据,但作为副本(因此可以单独分析日志数据)。
根据您的要求,您可以将此数据保存在环形缓冲区中,并且不断覆盖旧数据,或者在达到特定百分比时将其转储到磁盘。
答案 2 :(得分:-1)
编辑:现在有多个downvoters。请发表评论,以便我能妥善解决问题。谢谢!
您可以重新组织代码,以便您的记录器从缓冲区读取日期时间戳字符串,该缓冲区由其他一些线程更新N次(取决于您所需的分辨率)。每秒4次:
struct current_time_stamp {
char timestr_[4][16];
unsigned index_;
unsigned subsecond_;
const char *get () const { return timestr_[index_%4]; }
void update () {
// ... update string in timestr_[(index_+1)%4] ...
// ... if (index_ + 1)%4 is zero, recompute subsecond_
ATOMIC_INCREMENT(index_);
// ... also need a memory barrier for timestr_ update
}
};
每个日志的亚秒级分辨率将从高性能计数器读取。 DeadMG在Windows上建议QueryPerformanceTimer
,在Linux(和POSIX)上建议clock_gettime
。但是,如果这些实现的高估仍然很高,则可以使用内联汇编直接查询处理器上的时间戳计数器(有关x86,请参阅rdtsc
)。亚秒值是从结构中记录的值开始的delta'd,以获得适当的偏移量。
如果您能够以二进制格式记录时间戳,那么这将远离格式化问题。