Я записываю метки времени в моей программе с помощью следующего блока кода:
// 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 не активирован, в течение дня наблюдается линейный дрейф (700 микросекунд каждые 30 секунд или около того).
После исправления линейного дрейфа я обнаружил, что есть нелинейный компонент. Это может дрейфовать в и из сотен микросекунд в течение часов.
Второй график выглядит аналогично графикам, взятым по той же методике, что и выше, но с включенным NTP. В данных ожидаются большие вертикальные всплески, но колебание в минимуме удивительно.
Есть ли способ получить более точную временную метку, но сохранить разрешение в микросекундах / наносекундах? Это нормально, если часы отклоняются от фактического времени предсказуемым образом, но временные метки должны быть внутренне согласованными в течение длительных промежутков времени.
high_resolution_clock
не имеет гарантированных отношений с «текущим временем». Ваша система может или нет псевдоним high_resolution_clock
в system_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
};
Проблема в том, что если ваша машина не очень необычная, базовое оборудование просто не способный обеспечения особенно надежного измерения времени (по крайней мере, на шкалах, которые вы смотрите).
Будь то на ваших цифровых наручных часах или на вашей рабочей станции, большинство электронных тактовых сигналов внутренне генерируются кварцевый генератор. Такие кристаллы имеют как длительное (годы), так и кратковременное (минуты) изменение их «идеальной» частоты, причем наибольшим кратковременным компонентом является изменение с температурой. Необычное лабораторное оборудование будет иметь что-то вроде хрустальная печь который пытается поддерживать кристалл при постоянной температуре (выше температуры окружающей среды), чтобы свести к минимуму дрейф, связанный с температурой, но я никогда не видел ничего подобного на аппаратных вычислительных устройствах.
Вы видите эффекты неточности кристаллов по-разному в обоих ваших графиках. Первый график просто показывает, что ваш кристалл тикает с некоторым большим смещением от истинного времени, либо из-за изменчивости при изготовлении (это всегда было так плохо), либо из-за долговременного дрейфа (со временем это происходило) После включения NTP «постоянное» или среднее смещение от истины легко корректируется, поэтому вы ожидаете, что средний смещение нуля в течение некоторого большого промежутка времени (на самом деле линия, отслеживаемая минимальными провалами выше и ниже нуля).
В этом масштабе, однако, вы увидите меньшие краткосрочные изменения в действии. NTP периодически включается и пытается «исправить их», но кратковременный дрейф всегда присутствует и всегда меняет направление (вы можете даже проверить эффект увеличения или уменьшения температуры окружающей среды и увидеть его на графике).
Вы не можете избежать покачивания, но вы можете увеличить частоту настройки NTP, чтобы она была более тесно связана с реальным временем. Ваши точные требования не совсем ясны, хотя. Например, вы упоминаете:
Это нормально, если часы отклоняются от реального времени в предсказуемом
путь, но временные метки должны быть внутренне согласованы в течение
долгие отрезки времени.
Что означает «внутренне согласованный»? Если вы в порядке с произвольным дрейфом, просто используйте ваши существующие часы без настроек NTP. Если вы хотите что-то вроде времени, которое отслеживает в реальном времени «на больших таймфреймах» (то есть, оно не получает тоже не синхронизировано), почему вы можете использовать ваши внутренние часы в сочетании с периодическим опросом вашего «внешнего источника» и плавно изменять коэффициент регулировки, чтобы у вас не было «скачков» в видимом времени. Это в основном переосмысление NTP, но, по крайней мере, оно будет полностью под контролем приложений.