我正在尝试从NIC捕获数据包并将部分数据包有效负载保存为字符串。
必须存储的数据包的一部分是其日志时间,称为SysLog。每个数据包都有一个SysLog,格式如下:
Nov 01 03 14:50:25 TCP...[other parts of packet Payload]
可以看出,数据包SysLog没有年号。我的程序必须全年运行,因此我需要将年号添加到数据包SysLog并将SysLog转换为纪元时间。我必须存储的最后一个字符串是这样的:
1478175389-TCP, ….
我使用以下代码安静将Syslog转换为EpochTime。
tm* tm_date = new tm();
Std ::string time = Current_Year;
time += " ";
time += packet.substr(0,18);
strptime(time.c_str(), "%Y %b %d %T", tm_date);
EpochTime = timegm(tm_date);
currentYear方法:
std::string currentYear() {
std::stringstream now;
auto tp = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
size_t modulo = ms.count() % 1000;
time_t seconds = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
#if HAS_STD_PUT_TIME
#else
char buffer[25]; // holds "2013-12-01 21:31:42"
if (strftime(buffer, 25, "%Y", localtime(&seconds))) {
now << buffer;
}
#endif // HAS_STD_PUT_TIME
return now.str();
}
以上操作是我必须为每个数据包执行的操作。数据包速率为100000-1000000 pps,上面的代码安静非常耗时,特别是在currentYear()上。 一种可能的优化是删除currentYear()方法并保存 年份数字作为常数值。如前所述,我的计划必须全年运行,正如您所知,2017年即将到来。我们无法在2016年12月31日23:59:00更改二进制文件,也不想浪费时间计算年数!!
我需要一种更有效的方法来计算当前年份数而不为每个数据包运行它。
有可能吗?你对我有什么建议?
答案 0 :(得分:3)
一旦你获得了当前的日期和时间,基于此,计算明年1月1日午夜的纪元时间应该不会太难。
在计算年度到来之后的预期纪元时间之后,您需要做的就是在进行日志输入时将其与当前时间进行比较。如果它还没有达到预先计算的1月1日午夜时间,那么你知道这一年还没有到来。
因此,您根本不需要为每个数据包计算年份。只需要根据预先确定的1月1日午夜时间来检查当前时间,除非政治家决定更改您的时区,否则不应该改变,而所有这些都在运行......
答案 1 :(得分:1)
首先,您可以考虑currentYear()
返回int
(例如2016),可能会使用time(2),localtime_r(3),tm_year
字段....然后,您将避免使用C ++字符串。
然后,你说的是高分组率,所以你可能有一些event loop。你没有解释它是如何完成的(希望你使用一些库{la libevent,或至少你自己的poll(2) ....),但你可能只计算一次当前年份在该事件循环中每十分之一秒。或者让其他线程偶尔计算当前年份(你可能需要一个互斥体,或者使用std::atomic<int>
作为当年的类型......)
答案 2 :(得分:1)
以Jan
开头的日志条目更改年份,仅更改那些日志条目。
日志条目有时会出现故障,或者在之前的处理过程中保存时间戳。
从PC时钟附加年份会产生不良结果,例如
2016 Dec 31 23:59:58 normal 2016 Jan 01 00:01:01 printing time placed in packet by remote device, remote clock is running a bit fast 2017 Dec 31 23:59:59 printing timestamp saved locally two seconds before logging occurred 2017 Jan 01 00:00:03 back to normal
你不能只将本地时钟的年份与日志消息的月份...第二个连接起来。你必须分配避免大时钟跳跃的年份。
由于您无论如何都要尝试生成Unix时间(自纪元以来的秒数),首先将日志消息时间转换为Julian(自年初以来的秒数)并测试Julian是否小于或大于10百万(大约4个月)。
答案 3 :(得分:1)
你可以&#34;缓存&#34;您生成的字符串,仅在年份更改时更改它。它可能只是一个小小的&#34;改进取决于什么操作花费最多的时间。
//somewhere
static int currentYear = 0;
static std::string yearStr = "";
//in your function
auto now = std::chrono::system_clock::now();
auto tnow = system_clock::to_time_t(now);
auto lt = localtime(&tnow); //or gmtime depends on your needs.
if(currentYear != lt.tm_year)
{
yearStr = std::to_string(lt.tm_year + 1900);
currentYear = t.tm_year;
}
return yearStr;
我不确定静态是否对读取字符串的性能有任何负面/正面方面,或者由于缓存局部性,成员变量可能更好。你必须测试一下。
如果你在多个线程中使用它,你必须在这里使用互斥锁,这可能会降低性能(同样你必须测量它)。