Период таймера Windows по умолчанию составляет 15.6 мс – он тикает 64 раза в секунду. Когда программа увеличивает частоту таймера, растет потребление энергии, что сказывается на расходе батареи. При этом также расходуется вычислительная мощность компьютера, и даже больше, чем я думал – то есть компьютер начинает работать медленнее! Вот почему в течение многих лет Microsoft настоятельно не рекомендует разработчикам поднимать частоту таймера.
Почему же тогда почти каждый раз, когда я вижу разгон таймера, он вызван программой от Microsoft?
Узнать текущую частоту таймера Windows довольно просто с помощью утилиты clockres от sysinternals.
ClockRes v2.0 – View the system clock resolution
Copyright © 2009 Mark Russinovich
SysInternals – www.sysinternals.com
Maximum timer interval: 15.600 ms
Minimum timer interval: 0.500 ms
Current timer interval: 1.000 ms
Для увеличения времени работы компьютера от батарей текущий период таймера (который может быть изменен функцией timeBeginPeriod) должен быть равен 15.6 мс; но, как вы видите выше, какая-то программа изменила его на 1 мс, что эквивалентно дополнительным 936 тикам в секунду.
Поиск виновного – WPF
Процесс поиска виновного в увеличении частоты не так очевиден, но все-таки довольно прост. В командной строке администратора наберем
powercfg -energy duration 5
и в текущем каталоге появится файл energy-report.html, в котором мы, в частности, прочитаем:
The stack of modules responsible for the lowest platform timer setting in this process.
Requested Period 10000
Requesting Process ID 3932
Requesting Process Path
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
Calling Module Stack
C:\Windows\SysWOW64\ntdll.dll
C:\Windows\SysWOW64\winmm.dll
C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\wpfgfx_v0400.dll
C:\Windows\SysWOW64\kernel32.dll
C:\Windows\SysWOW64\ntdll.dll
Итак, Visual Studio 11, посредством использования WPF, запросила интервал в 1 мс, что и указано в отчете посредством несколько сбивающей с толку единицы измерения, равной 100 нс. Это известная проблема, связанная с WPF; все версии Visual Studio ведут себя так время от времени и, по-видимому, любое приложение, использующее WPF, может стать источником проблемы. Увеличение частоты может иметь смысл, когда программа пытается поддерживать постоянный фрейм рейт вывода, однако это не оправдывает WPF, поскольку она сохраняет высокую частоту таймера даже в том случае, когда никакой анимации не происходит.
Поиск виновного – SQL сервер
Другой процесс, часто виновный в увеличении частоты на моем компьютере – sqlservr.exe. Думаю, что он был установлен Visual Studio, но не уверен в этом, как не уверен, используется он или нет. В любом случае, SQL сервер не должен повышать частоту таймера; если таким образом предполагается повысить производительность приложения, то это больше похоже на костыль. И, как в случае с WPF, увеличение частоты нужно только тогда, когда сервер занят обработкой данных, а не постоянно.
Platform Timer Resolution:Outstanding Timer Request
A program or service has requested a timer resolution smaller than the platform maximum timer resolution.
Requested Period 10000
Requesting Process ID 2384
Requesting Process Path \Device\HarddiskVolume1\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Binn\sqlservr.exe
Поиск виновного – quartz.dll
У меня нет соответствующей записи из отчета powercfg, но C:\Windows\System32\quartz.dll является еще одним источником проблем с частотой таймера. Я даже толком не знаю, что такое этот Quarts (ну а мы-то знаем, что это не что иное, как Microsoft DirectShow – прим. пер.), но замечал, что иногда он расходует энергию зря.
Поиск виновного – Chrome
Обычно виновными становятся продукты Microsoft, однако к ним в компанию я добавляю еще Google Chrome. Когда я запускаю Chrome он постоянно увеличивает частоту таймера 1000 Гц, даже в том случае, когда компьютер работает от батареи, а я просматриваю простую HTML страницу. Привожу скриншот, фиксирующий преступление Chrome.
Поиск виновного – svchost.exe
Иногда svchost.exe увеличивает частоту таймера до 100 Гц. Это, конечно, не так страшно, как 1000 Гц, но все-таки раздражает. Особенно печально то, что я не могу определить, какой именно сервис это делает.
Общая трагедия – побеждает максимальная частота
Таймер Windows является глобальным ресурсом, он тикает с одинаковой частотой для всей системы целиком. Получается, что если какая-то программа увеличивает частоту таймера, то это сказывается на поведении всей системы.
Когда процесс вызывает функцию timeBeginPeriod, этот запрос частоты остается в силе до тех пор, пока не будет принудительно отменен с помощью timeEndPeriod или до конца работы приложения. Большинство программ (включая и мои тестовые, приведенные ниже) никогда не вызывают timeEndPeriod, полагаясь на системные средства очистки Windows. Это работает и вполне разумно для приложений, которым необходима повышенная частота таймера на всем протяжении исполнения. В противном случае хорошей идеей будет использование timeEndPeriod. По рекомендации Microsoft к приложениям второго вида относятся проигрыватели видео в режиме паузы и свернутые в трей игры. Сюда же можно включить веб-браузеры, которые в текущий момент не требуют высокой частоты таймера или при работе от батареи.
Так ли это важно?
Моим основным компьютером является ноутбук. Каждый день я использую его в автобусе и предпочитаю тратить батарею на что-то полезное, нежели чем на ненужные обращения к процессору 1000 раз в секунду.
Microsoft считает, что это важно. Они говорят: «нашей позицией остается последовательное улучшение энергоэффективности Windows ПК» и все-таки, даже 4 года спустя, сами, похоже, не исполняют свои собственные указания и не обращают внимания на свои же предупреждения: «некоторые приложения уменьшают период таймера до 1 мс, что приводит к сокращению времени работы мобильной системы на 25%».
Удобным способом измерения потребленной энергии является утилита Intel Power Gadget. На поддерживаемых процессорах Intel она покажет мощность, потребляемую упаковкой процессора в реальном времени с точностью до 0,01 Вт. На моем ноутбуке на платформе Sandy Bridge утилита показывает прирост в 0,3 Вт при повышении частоты таймера, что составляет почти 10% от стандартного потребления упаковкой процессора; применительно ко всей системе процент, конечно, будет меньше.
Увеличение на 0,3 Вт может выглядеть не таким большим, но есть пара моментов, заставляющих воспринимать его серьезно. Во-первых, если ваша программа работает, скажем, на 33 миллионах компьютеров (для Chrome это, наверное, даже заниженная оценка), увеличение частоты таймера приведет к потере примерно 10 МегаВатт энергии. Во-вторых, важность проблемы со временем будет только возрастать. Новые процессора с улучшенным объединенным таймером будут затрачивать на учащенные вызовы еще больше вычислительных мощностей.
Быстрые таймеры ухудшают производительность
Исполнение прерываний отнимает некоторую часть ресурсов компьютера, поэтому увеличение их количества в единицу времени должно несколько замедлить скорость его работы. Я проверил эту теорию, написав тестовую программу, крутящую циклы активности и докладывающую каждую секунду скорость своего исполнения. Во время работы программы я изменил частоту таймера, чтобы посмотреть его влияние на производительность.
Влияние было, причем существенное.
Я проделал быстрые тесты на двух компьютерах, так что точные цифры не стоит воспринимать слишком серьезно. Кроме того, они наверняка сильно зависят от аппаратной платформы, нагрузки и т.д. Однако результаты явно показали влияние ускорения таймера на производительность, оно составляет 2,5-5% — это больше, чем я предполагал. Степень замедления достаточно велика, чтобы заподозрить традиционный подход – повышение частоты таймера для увеличения производительности приложения – в контр-продуктивности.
Увеличение частоты таймера Windows не приводит ни к чему хорошему. При этом зря расходуется энергия и замедляется компьютер. Практика применения его во всех без разбора программах, висящих часами без активности, должна быть прекращена.
Вот результаты работы моей тестовой программы в графическом формате
20-секундный период по середине, где производительность неожиданно падает, совпадает с увеличением частоты таймера. Похожие результаты я получил во всех своих тестах, как при питании от батареи, так и от сети
Исходный код
Поскольку наука не делается без раскрытия исходного кода, привожу код своей тестовой программы.
#include “stdafx.h” #include <stdio.h> #include <Windows.h> LARGE_INTEGER g_frequency; const double kDelayTime = 1.0; double GetTime() { LARGE_INTEGER counter; QueryPerformanceCounter(&counter); return counter.QuadPart / double(g_frequency.QuadPart); } int g_array[1024]; int offset; int g_sum; void SpinABit() { for (int i = 0; i < ARRAYSIZE(g_array); ++i) { g_sum += g_array[i + offset]; } } void Stall() { double start = GetTime(); int iterations = 0; for (;;) { ++iterations; SpinABit(); double elapsed = GetTime() – start; if (elapsed >= kDelayTime) { printf(“%1.5e iterations/s\n”, iterations / elapsed); return; } } } int main(int argc, char* argv[]) { QueryPerformanceFrequency(&g_frequency); for (;;) Stall(); return 0; }
А вот программа, повышающая частоту таймера на 20 сек.
#include <stdio.h> #include <Windows.h> #pragma comment(lib, “winmm.lib”) int main(int argc, char* argv[]) { timeBeginPeriod(1); printf(“Frequency raised.\n”); Sleep(20000); printf(“Frequency lowered.\n”); // timeEndPeriod call is omitted because process // cleanup will do that. return 0; }
Не забудьте проверить частоту системного таймера перед запуском теста, иначе вы можете не увидеть разницы.
И потом исправьте код своих программ. Все, как один.
ссылка на оригинал статьи http://habrahabr.ru/company/intel/blog/186998/
Добавить комментарий