|
|
|
Стабилизация времени на серверах Windows 2003 и 2008 |
|
|
|
|
Обновлено:
Про свои эксперименты со временем я два месяца назад уже делал короткую заметку, теперь же хочу написать про свои изыскания более подробно. В качестве опорного счетчика системных часов в компьютере используется кварцевый источник частоты 64 Гц, соответственно если поделить 1 секунду на 64, получим 15.625 мс, и эта величина, выраженная в 100-наносекундных интервалах, выглядит так: 156250. Это значение, dwTimeAdjustment, возвращается функцией GetSystemTimeAdjustment. Надо отметить, что на некотором "железе" используется генератор с другой частотой (где-то писали, что в данном случае речь про так называемый таймер высокого разрешения HPET), и там базовая величина dwTimeAdjustment составляет 156000, но суть от этого не меняется - нам нужно знать опорный период, от которого мы и будем плясать (в дальнейшем я буду по умолчанию подразумевать 156250).
Помимо функции GetSystemTimeAdjustment, есть функция, которая выставляет новый период приращения системного времени: SetSystemTimeAdjustment. И действительно, если выставить, скажем, dwTimeAdjustment = 160000, то системное время начнет идти быстрее реального времени на 2.4%, то есть будет убегать вперед на полторы минуты каждый час.
Под термином "реальное время" я имею в виду UTC (плюс соответствующая поправка на часовой пояс). Для того, чтобы контролировать уход системных часов от реального времени, я использовал удобный компонент TIdSNTP, позволяющий получать текущее время от sntp-серверов. В последнее время я стал пользоваться московским сервером ntp.ix.ru (194.190.168.1), полный цикл отклика от которого составляет 4-8 мс. Усреднение по нескольким (4-5) последовательным измерениям позволяет достичь стабильности результата на уровне 1 мс. Абсолютное отклонение полученных от от сервера времени данных не превышает указанного диапазона 4-8 мс. Оба этих результата я полагаю достаточными.
До эпизода с "необъяснимым" уплыванием времени, описанного в предыдущей заметке, я не уделял вопросу времени пристального внимания. Меня вполне удовлетворяла установка утилиты по коррекции времени (Dimension 4). Однако этот эпизод сподвиг меня заняться решением проблемы стабильности хода часов на сервере. Поскольку у меня к тому моменту уже был описанный выше инструментарий (измерение реального времени и управление скоростью хода системного времени), я начал эксперименты.
В ходе этих экспериментов я обнаружил, что SetSystemTimeAdjustment странно работает на Windows Server 2008 - квант изменений оказался равен не 1, а 16. Эта же особенность проявилась и в Windows 7, в то время как в более старой Windows Server 2003 все ок - квант оказался равен 1. Меня удивило, что Microsoft умудрились испортить уже работающий механизм. Вот как они пишут про это сами: SetSystemTimeAdjustment May Lose Adjustments Less than 16. [Народ пишет, что в Windows 8 уже все поправили, но я еще не проверял. Впрочем, пишут, что там есть и глюки посерьезнее - на ютубе попадаются ролики, где время на восьмой винде уплывает на секунды за считанные минуты.] После такого "открытия" вполне логичным оказалось, что в dwTimeAdjustment не используется информация из младших 4 бит. То есть ближайшими доступными к 156250 значениями оказались 156240 и 156256 (они делятся на 16 нацело). Для меня осталась одна непринципиальная странность: переход от 156240 к 156256 происходит при переходе от 156250 к 156251. То есть для значений dwTimeAdjustment<=156250 мы получаем реальное значение dwTimeAdjustment=156240, а для dwTimeAdjustment>=156251 получаем реальные 156256. Это не похоже ни на округление, ни на простое отбрасывание младших 4 бит. Может, они тоже мучались с таким грубым квантованием, и решили в качестве компромисса хотя бы привязать переход к стандартным 156250. Впрочем, главное для меня - стабильное поведение, и изучать этимологию странностей я не стал. И удаленное от 156250 поведение переменной dwTimeAdjustment я не исследовал.
Не надо думать, однако, что старая Windows 2003 "победила" новые. У нее (равно как и у Windows XP) есть своя особенность: она выдает время Now() как раз с точностью кванта таймера, то есть 15-16 мс. В течение очередных 15 мс она выдает одно и то же значение, в то время как Windows 2008 (и Windows 7) честно увеличивают Now() каждую 1 мс. Поскольку для стабилизации времени на уровне 1 мс меня не устраивает точность в 15 мс, я придумал следующее - при каждом запросе времени от sntp-сервера я сперва дожидаюсь "среза" изменения значения Now(), и сразу после очередного фронта посылаю запрос sntp. Таким образом я добиваюсь того, что запрос к sntp посылается всегда в начале очередного 15-мс интервала. [Как потом оказалось, механизм оказался сыроват и не всегда срабатывает на загруженной вычислениями ОС.]
Помимо прочего, для увеличения стабильности результатов я применил усреднение по нескольким последовательным запросам (типичное значение = 5), фильтрацию "выбивающихся" значений (путем повторного запроса значений, улетевших от среднего больше указанной в программе величины, типично 2-3 мс), а также ограничение максимального времени запроса (типично 7-8 мс).
Параллельно с этими техническими улучшениями я последовательно сделал две версии стабилизатора времени. Но сначала я нашел наиболее близкие к реальному ходу времени значения dwTimeAdjustment:
Со скоростью dwTimeAdjustment=156253 системное время смещается от реального со скоростью 386 мс/сутки (4.47 ppm, parts per million - аналог процента, только в 10 тысяч раз меньше), а со скоростью 156252 - минус 170 мс/сутки (-1.97 ppm). Таким образом, разница между соседними значениями составила 4.47-(-1.97) = 6.44 ppm. Это с хорошей точностью совпадает с ожидаемой обратной величиной 1/156252 = 6.4 ppm.
Таким образом, сначала мне пришло в голову просто выставлять эти две величины по порядку при удалении от сервера на некую пороговую величину. Результат работы этой первой версии автоподстройки (которая обрела название auto1) приведен на следующем скриншоте.
Алгоритм поведения следующий. Выставляется повышенная скорость (156253), на ней "доезжает" до указанного порога отклонения от sntp-сервера (здесь 100 мс), после этого переключается на пониженную скорость 156252, на ней "доезжает" до минус порога (-100 мс), и вновь переключается на "повышенную". Время сверялось с sntp-сервером каждые 5400 сек (1.5 часа), и полный цикл "вверх-вниз", как видно из рисунка, занимал примерно за 2 суток.
В следующей версии автоподстройки скорости (auto2) я сделал то, что напрашивалось само собой: так называемую широтно-импульсную модуляцию (ШИМ). С ее помощью я фактически улучшил точность настройки величины dwTimeAdjustment до дробных значений. Для этого я организовал цикл переключения с одного значения dwTimeAdjustment на другое, соседнее, при этом изменение взаимной длительности этих циклов позволяет точно настроить среднюю скорость dwTimeAdjustment. Так, например, если на 50% времени цикла включать значение dwTimeAdjustment=156252, а на оставшиеся 50% dwTimeAdjustment=156253, то в итоге мы получим среднюю скорость = 156252.5. Результат работы этой системы виден на следующем скриншоте.
Обратите внимание на цифры под кнопкой auto2 - там последовательно задаются up rate (повышенная скорость), up period (время включения этой скорости, с), а также аналогичные параметры для пониженной скорости, dwn rate и dwn period. На приведенном рисунке полный цикл составляет 154+446 = 600 сек (10 минут), и средняя скорость при этом составляет 156252 + 154/600 = 156252.257. За время 10-минутного цикла системное время смещается туда и обратно на величину примерно 0.7 мс. Фактически мы получили ту же по сути картину, что и на предыдущем рисунке, только период цикла сократился с 2 суток до 10 минут, а сверка с атомным временем стала носить справочный, а не управляющий характер.
Как видно, такой системы подстройки оказалось достаточно, чтобы общий дрейф системы времени на этом сервере (с ОС Windows 2003) за 10 суток составил 7 мс. Видимо, это лучшее, что может дать кварцевый генератор на этом конкретном "железе". На графике на фоне общего дрейфа видны ежесуточные "холмы", связанные, как я полагаю, с периодическим температурным дрейфом "железа" в серверной. Я планирую понаблюдать за этим и дальше, однако уже ясно, что этот результат значительно лучше, чем простой подбор единственного значения dwTimeAdjustment, дающий стабильное "уплывание" времени на сотни миллисекунд в сутки.
Что касается абсолютной частоты кварцевого генератора в этом "железе", то она составила 1/(0.0156252257 с) = 63.999076 Гц, то есть 64 Гц минус 0.0014%. В итоге, абсолютное отклонение составило -14 ppm, а относительная стабильность (в текущем температурном режиме, за 10 суток) - не хуже 0.01 ppm.
В случае более новых операционных систем (Windows Server 2008 и Windows 7) вся эта благостная картина разрушается по причине, указанной выше - квант изменения величины dwTimeAdjustment в случае этих ОС грубее в 16 раз. И если мы стремимся к стабильности системного времени в районе 1 мс, то задать полный период цикла ШИМ равным 10 минутам мы уже не можем, иначе за это время системное время будет уплывать туда-сюда на 15 мс. Сделать его совсем малым мы тоже не можем, иначе пострадает сама точность ШИМ-регулирования. Я остановился на периоде 100 сек, в течение которого дрейф составляет приемлемые плюс-минус 2.5 мс, а также позволяет с удовлетворительной точностью выставить параметры ШИМ-регулятора. В качестве примера рассмотрим следующий скриншот (Windows 2008).
Как отмечалось выше, несмотря на то, что задаются соседние параметры dwTimeAdjustment, равные 156251 и 156250, в действительности это соответствует значениям 156256 и 156240. Подобранные настройки ШИМ-цикла (76.6 секунд вверх, 23.4 вниз) дают средний dwTimeAdjustment = 156240 + 16*76.6/100 = 156252.256 (величина, близкая к приведенной выше для сервера Windows 2003, что неудивительно, поскольку обе виртуальные ОС крутятся на одном "железе"). Как видно из графика, разброс системного времени за 4 суток составил около 6 мс.
Следующим логичным шагом была бы подстройка параметров ШИМ-регулятора, скажем, раз в сутки (или чаще) исходя из графика отклонения системного времени. По сути, совмещение auto1 и auto2. Сделаю ли я этот шаг, я уже не уверен, поскольку существуют более серьезные и к настоящему времени необъяснимые факторы. Все протестированные ОС могут как скачком (Windows 7 на ноутбуке легко прыгает на 100 мс), так и плавно (Windows 2008 как-то раз отдрейфовала за несколько часов на минус 100 мс, а затем прекратила как ни в чем не бывало). Я попытался найти источник этого своеволия, но пока тщетно: служба времени отключена, в расписании я тоже ничего не нашел. Гугл мне пока тоже ничем не помог - мало кого интересует подобная ловля блох, люди просто подправляют системное время разными "атомными" утилитами, а скачки времени при таких поправках их не беспокоят.
В итоге можно считать, что задача стабилизации системного времени в Windows в первом приближении выполнена.
|
|
|
|
Просмотров: 3477 |
|
|
|
----
|
|
|
Архив сайта |
|
|
|
|
|
|
|