Какой самый эффективный способ программно проверить, изменился ли год

Я пытаюсь перехватить пакеты с сетевого адаптера и сохранить часть полезной нагрузки пакета в виде строки.

На части пакета, который должен быть сохранен, находится его время регистрации, известное как 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);

Текущий год метод:

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 год. Мы не можем изменить наш двоичный файл по состоянию на 31.12.2016 23:59:00, а также не хотим тратить время на вычисление номера года !!

Мне нужен более эффективный способ рассчитать номер текущего года без запуска его для каждого пакета.

Является ли это возможным? Каково ваше предложение для меня?

2

Решение

Как только вы получите текущую дату и время, основываясь на этом, не должно быть слишком сложно рассчитать, какое будет время эпохи для полуночи следующего января 1-го января.

После расчета ожидаемого времени эпохи, когда наступит год, все, что вам нужно сделать, — это сравнить его с текущим временем при внесении записи в журнал. Если он не достиг предварительно рассчитанного полуночного времени 1 января, вы знаете, что год еще не наступил.

Таким образом, вам не нужно рассчитывать год для каждого пакета вообще. Просто нужно сравнить текущее время с предварительно рассчитанным временем полуночи 1 января, которое не должно меняться, если политики не решат изменить ваш часовой пояс, пока все это работает …

3

Другие решения

Год изменяется для записей в журнале, начиная с Janи только те записи журнала.

Записи журнала иногда выходят из строя или содержат метку времени, сохраненную во время предыдущей обработки.

Присоединение года с часов ПК даст плохие результаты, такие как

2016 Дек 31 23:59:58 нормально
2016 янв 01 00:01:01 время печати в пакете удаленным устройством, часы работают немного быстрее
2017 Дек 31 23:59:59 печать временной метки сохранена локально за две секунды до регистрации
2017 янв 01 00:00:03 вернуться в нормальное состояние

Вы не может просто объедините год местных часов с месяцем … секунда сообщения журнала. Вы должны назначить год, который избегает больших скачков часов.

Поскольку вы все равно пытаетесь определить время Unix (секунды с начала эпохи), начните с того, что превратите время сообщения журнала в юлианское (секунды с начала года) и проверьте, меньше или меньше, чем, скажем, юлианский 10 миллионов (примерно 4 месяца) ).

1

Вы можете «кэшировать» созданную вами строку и изменять ее только при изменении года. Это может быть лишь небольшое улучшение в зависимости от того, какие операции занимают больше всего времени.

//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;

Я не уверен, что у static есть какие-либо отрицательные / положительные аспекты производительности чтения строки, или переменная-член может быть лучше здесь из-за локальности кэша. Вы должны проверить это.

Если вы используете это в нескольких потоках, вы должны использовать здесь мьютекс, который, вероятно, снизит производительность (опять же, вы должны измерить это).

1

Во-первых, вы могли бы рассмотреть currentYear() возвращая int (например, 2016), вероятно, с Время (2), localtime_r (3), tm_year поле …. Затем вы будете избегать создания строк C ++.

Затем вы говорите о высокой скорости передачи пакетов, поэтому у вас, вероятно, есть некоторые цикл событий. Вы не объясняете, как это делается (надеюсь, вы используете какую-то библиотеку Libevent, или, по крайней мере, ваш собственный цикл вокруг Опрос (2)….), но вы можете вычислять текущий год только один раз каждую десятую секунды в цикле событий. Или используйте какой-нибудь другой поток, который время от времени вычисляет текущий год (вам, вероятно, понадобится мьютекс, или используйте std::atomic<int> как тип текущего года …)

1
По вопросам рекламы [email protected]