Хотя сведение к минимуму прерываний от часов для процессоров, спящих в периоды отсутствия обслуживания истечения времени таймеров, дает большой прирост более продолжительных интервалов C-состояния, при величине кванта времени в 15 мс многие таймеры, скорее всего, выстроятся в очередь к любому заданному исполнителю, и срок их действия будет истекать довольно часто, даже если будет задействован только процессор 0.
Сокращение количества программной работы по обслуживанию истечения времени таймеров поможет не только сократить задержки (будет требоваться меньше работы на уровне DISPATCH_LEVEL), но и даст возможность другим процессорам еще дольше находиться в состоянии спячки (процессоры просыпаются только для обслуживания таймеров с истекшими сроками, а уменьшение количества истечений времени таймеров приводит к более длительным спящим периодам).
По правде говоря, на спящее состояние реально влияет не столько количество таймеров с истечением времени (оно влияет на задержку), сколько периодичность истечения времени этих таймеров — 6 таймеров, время которых истекает по одному и тому же исполнителю предпочтительнее 6-ти таймеров, время которых истекает по 6-ти разным исполнителям. Поэтому для полной оптимизации продолжительности времени простоя ядру нужно задействовать механизм объединения (coalescing mechanism) для объединения отдельных исполнителей таймеров в единственный исполнитель с множественными истечениями времени.
Объединение таймеров работает на предположении, что большинство драйверов и приложений пользовательского режима не особо заботятся о точном периоде срабатывания своих таймеров (за исключением, к примеру, мультимедийных приложений). Эта область «не особо заботящихся» становится шире по мере роста исходного периода таймера — приложение, пробуждающееся каждые 30 с, не будет, наверное, возражать против пробуждения вместо этого каждые 31 или 29 с, а драйвер, осуществляющий опрос каждую секунду, сможет, наверное, опрашивать устройство каждую секунду плюс-минус 50 мс, не имея при этом особых проблем.
Важной гарантией, от которой зависит большинство периодических таймеров, является тот факт, что период их сигналов остается постоянным в пределах определенного диапазона. К примеру, если настройка таймера была изменена на выдачу сигнала каждую секунду плюс 50 мс, он продолжает постоянно выдавать сигнал в пределах этого диапазона, не выдавая его иногда через 2, а иногда и через полсекунды. Но даже при этом не все таймеры готовы к объединению в более грубые группы детализации, поэтому Windows включает этот механизм только для таймеров, которые сами себя пометили, как имеющие такую возможность либо через API-функцию ядра KeSetCoalescableTimer, либо через ее копию пользовательского режима SetWaitableTimerEx.
С помощью этих API-функций разработчики драйверов и приложений имеют возможность предоставить ядру максимум допустимых отклонений (или приемлемых отсрочек), которые выдержит их таймер, что определяется как максимальное количество времени за пределами запрошенного периода, при котором таймер все еще будет правильно работать.
Рекомендуемое минимальное допустимое отклонение составляет 32 мс, что соответствует примерно двойному 15,6-миллисекундному такту часов — любое меньшее значение не приведет к объединению, поскольку таймер с истечением срока не возможно даже будет переместить с одного такта часов на другой. Независимо от указанного допустимого отклонения Windows приводит таймер к одному из четырех наиболее предпочтительных интервалов объединения: 1 с, 250 мс, 100 мс или 50 мс.
Когда допустимая задержка устанавливается для периодического таймера, Windows использует процесс, называемый смещением (shifting). Смещение заставляет таймер дрейфовать между периодами, пока он не будет выровнен по наиболее оптимальному кратному периоду интервала в пределах предпочтительного объединяющего интервала, связанного с заданным допустимым отклонением (который затем кодируется в заголовке диспетчера).
Для абсолютных таймеров список предпочтительных объединительных интервалов сканируется, и предпочтительное время истечения срока генерируется на основе ближайших допустимых объединительных интервалов к максимально допустимым отклонениям, указанным вызывающей программой. Такое поведение означает, что абсолютные таймеры всегда вытесняются как можно дальше от точки реального истечения времени, чтобы рассредоточить таймеры как можно дальше и создавать более продолжительные времена спячки процессоров.
Теперь, зная о возможности объединения таймеров предположим, что для всех таймеров были указаны допустимые отклонения и тем самым указана допустимость объединения. По одному из сценариев Windows может принять решение по объединению таймеров, как показано на рисунке. Обратите внимание, что теперь процессор 1 получает всего лишь три прерывания от часов, что существенно увеличивает периоды спячки, и способствует достижению низшего C‑состояния.
Кроме того, сокращается объем работы, относящейся к некоторым прерываниям от часов на процессоре 0, что, возможно, устраняет задержки, требуемые для снижения уровня до DISPATCH_LEVEL при каждом прерывании от часов.
Кроме того, сокращается объем работы, относящейся к некоторым прерываниям от часов на процессоре 0, что, возможно, устраняет задержки, требуемые для снижения уровня до DISPATCH_LEVEL при каждом прерывании от часов.