2016-11-03 10 views
2

Я пытаюсь захватить пакеты из NIC и сохранить часть полезной нагрузки пакета в виде строки.Какой самый эффективный способ программно проверить, изменился ли год?

На части пакета, который должен быть сохранен, является его время журнала, известное как SysLog. Каждый пакетов имеет SysLog в следующем формате:

Nov 01 03 14:50:25 TCP...[other parts of packet Payload] 

Как можно видеть, пакет SysLog не имеет год номер. Моя программа должна работать круглый год, поэтому мне нужно добавить Year Number в пакет 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); 

The 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 п.п., и вышеуказанный мир кода очень трудоемкий на текущий год(). Одна из возможных оптимизаций - удалить метод currentYear() и сохранить число Year в качестве постоянного значения. Как было сказано ранее, моя программа должна запускаться круглый год, и, как вы знаете, 2017 год идет. Мы не можем изменить наш бинарный файл 31/12/2016 23:59:00, а также не хотим тратить время на вычисление номера года!

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

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

+2

Вы профилировали то, что именно занимает больше всего времени? Если это преобразование строк, у меня может возникнуть идея, но не уверен, что требуется много времени. Кроме того, по модулю это дорогостоящая операция. – Hayt

+0

Вы не можете сделать это безошибочно, если исходные временные метки являются неполными. –

+3

Я удалил тэг C с тех пор, как вы используете C++ (C и C++ - разные языки), и добавил тег C++ 11, так как вы используете ключевое слово 'auto' и' chrono' library – wasthishelpful

ответ

3

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

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

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

+2

_ «если политики не решат чтобы изменить часовой пояс, пока все это работает ... »_ Не исключено, что второй год может быть объявлен в течение года за тот же год. На самом деле это разумно обыденно. Вы должны обновлять «эпоху» время от времени. (Я принимаю UTC) –

+0

Скорость передачи пакетов составляет 500000 pps в среднем. сколько будет предложено выступление «если»? –

+1

@LightnessRacesinOrbit Это было бы верно, только если ваш часовой пояс является «правильным/....» часовым поясом, который отсчитывает секунды прыжка. Это очень редко на практике. Обычные часовые пояса игнорируют секунды прыжка, а ntpd медленно перемещает системные часы, замедляя их или ускоряя в течение дня, чтобы поглотить второй прыжок. С эпохи было добавлено ~ 30 секунд, и если время эпохи должно было включать в себя секунды прыжка, то время: 00-секундная эпоха больше не будет равномерно делиться на 60. Но это все еще так. Если ваш TZ не является «right/America/New_York», вместо «America/New_York», например. –

1

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

Затем вы говорите о высокой скорости передачи пакетов, поэтому у вас, вероятно, есть event loop. Вы не объясняете, как это делается (надеюсь, вы используете некоторую библиотеку à la libevent или, по крайней мере, свой собственный цикл вокруг poll(2) ....), но вы можете вычислить текущий год только раз в десятую часть секунды в этом цикле событий , Или вы можете использовать некоторые другие потоки в текущем году (вам, вероятно, потребуется мьютекс, или используйте std::atomic<int> как тип текущего года ...)

1

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

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

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

 
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-время (секунды с эпохи) в любом случае, начните с того, что время сообщения журнала должно быть переведено на Джулиан (секунды с начала года) и проверьте, меньше или меньше юлиан, чем 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; 

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

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