Как правильно сравнивать скорость разных версий программы в Windows
· Обновлено: · Го Комура · Windows, Бенчмарк, Производительность, Профилирование, Управление питанием
История изменений (1 обновлений, последнее 30 Aug 2026)
Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.
- Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
- Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.21619701)
Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.
Го Комура (2026). Как правильно сравнивать скорость разных версий программы в Windows. KomuraSoft LLC. https://comcomponent.com/ru/blog/2026/03/16/002-windows-benchmark-comparing-program-versions/
- DOI (зарегистрированный архив)
- 10.5281/zenodo.21619701
- DOI (последняя зарегистрированная версия)
- 10.5281/zenodo.21619702
Нужно сравнить версии A и B программы в Windows. Худшее, что можно сделать, — запустить каждую по одному разу на одной машине и сказать: «Похоже, B быстрее примерно на 8%».
Эти 8% действительно могут быть разницей в коде. Но на практике в бенчмарке на Windows часто оказывается, что дело в Power mode (режиме питания), Power plan (схеме электропитания), тепловом режиме, фоновом обновлении, индексации поиска, антивирусном сканировании, affinity, порядке запусков или состоянии кэша. Дальше идёт неэффектная работа: снимать эти условия по одному.
flowchart TB
accTitle: Что стоит за «похоже, быстрее на 8%»
accDescr: Разница после одного запуска каждой версии может быть разницей в коде, но часто это питание, тепло, шум или кэш; условия нужно снимать по одному.
one1["Запустить по одному разу и сравнить"] --> dif2["Получается «похоже, быстрее на 8%»"]
dif2 -->|"может быть"| code1["действительно разница в коде"]
dif2 -->|"частая причина"| env1["питание, тепло, шум, кэш"]
env1 --> crush1["снимать условия по одному"]
Рис. 1: Разница с одного запуска — ещё не разница в коде. Пока условия не сняты, утверждать нельзя.
В статье собраны способы сравнивать скорость выполнения разных версий программы в Windows как можно ближе к разнице в самом коде.
Основной ориентир — Windows 11, но большая часть вроде powercfg и start так же работает и в Windows 10.
Термины, которые лучше зафиксировать заранее
В тексте встречаются английские термины. Чтобы не споткнуться при первом появлении, сводим их здесь.
| Термин | Смысл |
|---|---|
| ETW | Event Tracing for Windows. Штатная подсистема трассировки Windows. Можно вместе записывать события ОС, драйверов и приложений |
| WPR / WPA | Windows Performance Recorder и Windows Performance Analyzer. Инструмент записи трассировок ETW и инструмент, которым их открывают и анализируют. Оба входят в Windows ADK |
| clean boot | Процедура: остановить службы и приложения автозагрузки, не относящиеся к Microsoft, и загрузиться в минимальной конфигурации. Её используют, чтобы снизить шум от постоянно живущих программ |
| PGO | Profile-Guided Optimization. Механизм: статистику ветвлений и вызовов с одного запуска используют в решениях об оптимизации следующего билда. Условия сборки меняются, поэтому это пункт проверки, действительно ли сравнивают одно и то же |
| p95 / p99 | Перцентиль. Если все запуски упорядочить от быстрого к медленному, это значение на позиции 95% / 99% снизу. «Один запуск из двадцати медленнее этого» — это p95 |
| NUMA | Non-Uniform Memory Access. Конфигурация, в которой расстояние от CPU до памяти не одинаково. Скорость доступа к памяти зависит от того, на каком узле выполняется код |
| core parking | Механизм управления питанием: при низкой нагрузке неиспользуемые логические процессоры переводят в сон |
Сначала выводы
Если свести к тому, что реально повышает воспроизводимость, это шесть пунктов.
-
Сначала решить, что именно сравниваете Нужна разница в коде или реальный пользовательский опыт. От этого зависит, какие условия среды выравнивать.
-
Записывать Power mode и Power plan как разные вещи В Windows, если смешать их, сравнение легко превращается в сравнение политики энергосбережения самой ОС.
-
Отделять холодный первый запуск от установившегося состояния после прогрева Быстрее только в первый раз или медленнее только к концу серии — не редкость.
-
Чередовать запуски, например A→B→A→B Если сначала прогнать все A, а потом все B, на одну сторону ляжет перекос тепла и фоновой активности.
-
Смотреть не только среднее, но и медиану с разбросом Один выброс сильно искажает картину. Среднее хрупче, чем кажется.
-
Если разница мала, доходить до причины через ETW / WPR Спор «по ощущению» оставляет оба утверждения без опоры, и разговор никуда не движется.
На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 25, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle
Сначала решить, что именно сравниваете
«Сравнение скорости» звучит как одно действие, но на деле это два разных сравнения.
1. Сравнение, в котором нужна разница в коде
Сравнение, в котором нужно узнать, стала ли быстрее сама реализация после смены алгоритма, структуры данных, оптимизаций компилятора, обновления runtime.
В этом случае шум среды срезают насколько возможно. Отдельный сеанс под бенчмарк, фиксированный Power mode, выключенные уведомления, подавление индексации поиска и синхронизации, при необходимости — вплоть до clean boot.
2. Сравнение, в котором нужен реальный пользовательский опыт
Сравнение, в котором нужно узнать, какой скорость ощущается пользователем в повседневной Windows после выпуска.
Здесь нельзя убирать весь шум, который есть в реальности. Сравнение в «правдоподобной повседневной среде» с синхронизацией OneDrive, Defender, уведомлениями и обычными настройками питания ближе к реальному результату.
Если смешать эти два вида, вывод перекашивается. Обычное дело: «в лаборатории на 12% быстрее, в реальности — в пределах погрешности» или «в реальности быстрее, а по CPU time не меняется».
flowchart TB
accTitle: Два вида сравнения не смешивать
accDescr: Если нужна разница в коде, шум среды срезают; если нужен реальный пользовательский опыт, измеряют в повседневной среде с шумом. Смешать два вида — перекосить вывод.
q5["Что именно сравниваете"] -->|"разница в коде"| lab1["лаборатория со срезанным шумом"]
q5 -->|"реальный пользовательский опыт"| real1["повседневная среда с шумом"]
q5 -.->|"если смешать"| twist2["вывод перекашивается"]
Рис. 2: Среда, которую нужно выравнивать, противоположна в зависимости от цели, поэтому вид сравнения выбирают в самом начале.
Главные причины разброса результатов в Windows
Сначала грубо перечислим, что двигает результаты.
| Слой | Источник разброса | Типичный пример |
|---|---|---|
| Оборудование | CPU / GPU, память, SSD, охлаждение | тонкий ноутбук, есть или нет охлаждающая подставка |
| Прошивка | BIOS / UEFI, управление OEM | политика энергосбережения, управление вентилятором |
| ОС | Windows build, драйверы, состояние обновлений | на том же ПК поведение меняется после обновления |
| Питание | AC / DC, Power mode, Power plan | на батарее это уже другой мир |
| Тепло | температура в комнате, вентилятор, предыдущая нагрузка | turbo только на первом запуске, просадка к концу серии |
| Фон | Update, Defender, синхронизация, уведомления | во время запуска идёт сканирование или синхронизация |
| Планирование | приоритет, affinity, NUMA | размещение по CPU зависит от машины |
| Данные / кэш | кэш ОС, кэш приложения | медленно только в первый раз, быстро только со второго |
| Условия сборки | Debug / Release, PGO, есть логи или нет | по сути сравнивают разные вещи |
Итого: даже «та же машина с Windows» — другой эксперимент, если условия не выровнены.
flowchart TB
accTitle: Без выровненных условий это другой эксперимент
accDescr: Даже измерение на той же машине с Windows — по сути другой эксперимент, пока не выровнены многослойные условия от железа до питания, тепла, фона и сборки. Сравнение начинается только после фиксации условий.
same1["Измерять на той же машине с Windows"] -.->|"условия не выровнены"| oth1["по сути другой эксперимент"]
same1 -->|"зафиксировать и записать условия по слоям"| cmp1["только тогда это сравнение"]
Рис. 3: Даже при той же машине сравнение не держится, пока не выровнены условия, которые пересекают слои.
Power mode и Power plan рассматривать отдельно
Здесь это особенно важно.
В Windows есть Power mode (режим питания) в приложении «Параметры» и традиционный Power plan (схема электропитания) — схема, которую видно через powercfg.
Они похожи внешне, поэтому их смешивают. Небрежное обращение делает условия сравнения размытыми, и воспроизводимость результата пропадает.
В приложении «Параметры» Windows Power mode выбирают в Settings > System > Power & battery.
По документации Microsoft для Plugged in / On Battery отдельно переключают Best power efficiency, Balanced и Best performance. Кроме того, смена Power mode влияет на связанные с питанием настройки и на поведение PPM (Processor Power Management). То есть одной этой разницы достаточно, чтобы могла смениться политика core parking и масштабирования производительности.
Power plan, напротив, — традиционная схема электропитания вроде Balanced или High performance.
Её смотрят командами powercfg /list и powercfg /getactivescheme.
Сложность в том, что в Windows есть и overlay Power mode, и Power plan. Если нарисовать связь, получается так:
flowchart TB
subgraph upper["Верхний слой: Power mode — overlay"]
direction LR
M1["Best power efficiency"]
M2["Balanced"]
M3["Best performance"]
end
subgraph lower["Нижний слой: Power plan — схема электропитания"]
direction LR
P1["Balanced"]
P2["High performance"]
P3["custom plan"]
end
UI["Параметры: Power mode в Power and battery"] --> upper
CLI["переключение через powercfg /setactive"] --> lower
upper --> PPM["действующие параметры питания: PPM и подгруппа graphics"]
lower --> PPM
AC["питание от сети или от батареи"] --> PPM
PPM --> RESULT["потолок частоты / core parking / масштабирование производительности"]
Рис. 4: Два слоя — Power mode (overlay) и Power plan — вместе с AC/DC задают параметры питания, которые реально действуют.
Одного верхнего слоя или одного нижнего недостаточно, чтобы определить фактическое поведение. Поэтому в результате бенчмарка запишите как минимум:
- питание от сети или от батареи
- какой Power mode
- какой Active power plan
Результат бенчмарка без этих трёх пунктов потом не восстановить.
flowchart TB
accTitle: Три пункта, которые записывают всегда
accDescr: Если вместе с результатом не записать питание от сети или от батареи, какой Power mode и какой Active power plan, условия потом нельзя восстановить.
r1["питание от сети или от батареи"] --> rec2["записать вместе с результатом"]
r2["Power mode"] --> rec2
r3["Active power plan"] --> rec2
rec2 --> rst1["условия можно восстановить позже"]
Рис. 5: Три пункта вокруг питания — минимум, без которого сам результат нельзя воспроизвести.
Какие условия питания фиксировать в первую очередь
-
Ноутбук всегда сравнивать при питании от сети Работа от батареи легко вводит ограничение, которого вы не планировали.
-
Зафиксировать Power mode Для бенчмарка сначала пробуют
Best performance. -
Записать Active power plan Текущее значение сохраняют через
powercfg.
powercfg /list
powercfg /getactivescheme
Вывод powercfg /list в документации Microsoft показан в таком виде. У активной схемы в конце строки стоит *. В японской среде заголовок и имена схем выводятся по-японски.
Existing Power Schemes (* Active)
-----------------------------------
Power Scheme GUID: {guidPlan1} (Balanced) *
Power Scheme GUID: {guidPlan2} (Power saver)
Полученный здесь GUID копируют как есть в поле power_plan файла результатов. Важно оставить GUID, а не имя. Даже при одном и том же «Balanced» это может быть другая схема — копия или настроенная вручную.
- При необходимости переключиться на High performance
# Balanced
powercfg /setactive 381b4222-f694-41f0-9685-ff5bb260df2e
# High performance
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
Можно ли переключить Power mode из командной строки?
Здесь легко застрять. В опубликованном списке параметров командной строки powercfg нет опции, которая заново выбирает сам Power mode (overlay). Штатный путь — через Settings > System > Power & battery в приложении «Параметры».
При этом powercfg умеет читать и писать значения настроек overlay-схемы. В документации сказано:
- если в
powercfg /qпередать alias overlay и подгруппу, можно прочитать настройки со стороны overlay powercfg /setacvalueindexи/setdcvalueindexработают и для overlay-схемы- если схему не указать, целью становится сейчас активный overlay (если overlay нет — текущий Power plan)
- список alias смотрят через
powercfg /aliases
То есть из командной строки можно «прочитать и подкрутить содержимое сейчас действующего overlay», но не «выбрать, какой overlay активен». Как воспроизводимая процедура бенчмарка реалистичнее зафиксировать Power mode вручную в приложении «Параметры» и записать это значение в результат. В инструкции явно пишут «Power mode = Best performance», и перед каждым запуском проверяют это на экране.
flowchart TB
accTitle: Что powercfg умеет и чего не умеет
accDescr: powercfg умеет читать и подкручивать содержимое действующего overlay, но опции сменить выбранный overlay нет, поэтому Power mode фиксируют вручную в приложении «Параметры» и записывают значение.
pc1["powercfg"] -->|"умеет"| rw1["читать и подкручивать содержимое overlay"]
pc1 -.->|"не умеет"| sel1["сменить, какой overlay выбран"]
sel1 --> hand1["зафиксировать вручную в «Параметрах» и записать"]
Рис. 6: Выбранный overlay командой не сменить, поэтому его фиксируют вручную и записывают.
«High performance нет в списке» — обычная ситуация
И здесь часто застревают. По документации Microsoft на устройствах с Modern Standby разрешены только Balanced или схемы, производные от Balanced. Поэтому это не обязательно поломка вида «High performance пропал». Возможно, так устроена эта модель.
Кроме того, Microsoft пишет: если Power mode нельзя изменить, возможно выбран custom power plan, поэтому сначала стоит попробовать Balanced. Когда элементы управления Power mode не реагируют, подозревать нужно в первую очередь это.
flowchart TB
accTitle: Как читать случай, когда High performance нет
accDescr: На устройствах с Modern Standby разрешены только Balanced или производные схемы, поэтому отсутствие High performance — конструкция; если UI Power mode не реагирует, сначала подозревают custom plan и пробуют Balanced.
nohp1["High performance нет в списке"] --> ms1["если есть Modern Standby, так и задумано"]
nomv1["UI Power mode не реагирует"] --> cst1["подозрение на custom plan"]
cst1 --> bl1["сначала попробовать Balanced"]
Рис. 7: Отсутствие схемы или неподвижный UI — ещё не поломка. Сначала смотрят конструкцию модели и выбранную схему.
Снижать фоновый шум
Windows даже тогда, когда вы хотите мерить тихо, в фоне гоняет обновления, индексацию и сканирование. Сначала уменьшают этот объём.
Сначала перезагрузиться и подождать, пока система успокоится
После смены настроек перезагружаются один раз. Сразу после входа не запускают, а ждут несколько минут. Сразу после загрузки ещё заняты обновления, индексация, синхронизация, Defender и постоянно живущие программы.
flowchart TB
accTitle: Перезагрузиться и подождать, пока система успокоится
accDescr: После смены настроек перезагружаются один раз; сразу после загрузки ещё идут обновления, индексация, синхронизация и Defender, поэтому сразу после входа не запускают, а ждут несколько минут и только потом измеряют.
chg1["Изменить настройки"] --> rb1["перезагрузиться один раз"]
rb1 --> wt1["после входа подождать несколько минут"]
wt1 --> ms2["только потом начинать измерение"]
rb1 -.-> nzz1["сразу после загрузки постоянно живущие программы ещё заняты"]
Рис. 8: Измерение начинают только после того, как фоновая активность после перезагрузки успокоилась.
Для строгого сравнения использовать clean boot
Microsoft описывает процедуру, которой через clean boot приходят к минимальной конфигурации автозагрузки.
Службы не от Microsoft останавливают в msconfig, приложения автозагрузки (Startup apps) отключают в диспетчере задач.
Это сильно снижает шум. Но это уже далеко от повседневной среды, поэтому подходит для «лабораторного сравнения, в котором нужна разница в коде».
Заглушить уведомления
Баннер уведомлений Windows выглядит мелочью и мешает сильнее, чем кажется. Дело не только в визуальной помехе: он может менять тайминг выполнения, фокус и фоновую активность приложений.
Включают Do not disturb вручную или как минимум выключают уведомления на время бенчмарка.
Подавить индексацию поиска и синхронизацию
Если объект бенчмарка читает много файлов, пишет много артефактов или многократно пересобирает дерево исходников, индексация поиска и облачная синхронизация тихо бьют по измерению.
- Исключить каталог бенчмарка из области индексации
- Остановить синхронизацию OneDrive / Dropbox / Google Drive и подобных сервисов
- Закрыть браузер, Teams, Discord, Slack
Здесь нет эффектности, но когда это влияет — влияет сильно.
flowchart TB
accTitle: Шум, который бьёт по бенчмарку с большим объёмом файлов
accDescr: В бенчмарке, который много читает и пишет файлы, индексация поиска, облачная синхронизация и постоянно живущие программы бьют по измерению; исключения и остановка снижают шум.
ix1["индексация поиска"] --> hit1["бьёт по бенчмарку с большим объёмом файлов"]
sy1["облачная синхронизация"] --> hit1
ap2["постоянно живущие программы"] --> hit1
hit1 --> cutn1["исключения и остановка снижают шум"]
Рис. 9: Чем больше бенчмарк читает и пишет файлов, тем сильнее работает остановка индексации и синхронизации.
Сравнение без выравнивания тепла по сути сравнивает тепло
CPU и GPU меняют тактовую частоту, когда они холодные и когда уже прогрелись. Даже тот же код на каждом запуске идёт в других условиях. Особенно это заметно на ноутбуке, тонком мини-ПК и компактном настольном ПК.
flowchart TB
accTitle: Как тепло меняет условия
accDescr: CPU и GPU меняют тактовую частоту в холодном состоянии и после прогрева, поэтому даже тот же код на каждом запуске идёт в других условиях; сравнение без выравнивания тепла сравнивает тепло.
cold1["Запуск в холодном состоянии"] --> hot1["прогрев меняет тактовую частоту"]
hot1 --> vary1["условия меняются на каждом запуске"]
vary1 -.-> heatc1["сравнение без выравнивания тепла сравнивает тепло"]
Рис. 10: Тактовая частота ходит вместе с теплом. Если тепловые условия не выровнены, сравнивают охлаждение, а не код.
Правила, которых стоит держаться
- Выравнивать температуру в комнате насколько возможно
- Зафиксировать, как стоит ноутбук
- Зафиксировать конфигурацию адаптера питания, док-станции и внешних дисплеев
- Не делать тяжёлую работу непосредственно перед бенчмарком
- Измерять первый запуск и установившееся состояние отдельно
Порядок запусков — чередовать
Избегают схемы «сначала 10 раз A, потом 10 раз B». Иначе ляжет перекос тепла, кэша и фоновой активности.
Рекомендуется один из вариантов:
A B A B A B ...A B B A A B B A ...- заранее сгенерировать случайный порядок и идти по нему
flowchart TB
accTitle: Порядок запусков меняет, как копится перекос
accDescr: Если сначала прогнать все A, а потом все B, перекос тепла, кэша и фоновой активности ляжет только на одну сторону; чередование или случайный порядок распределяет перекос на обе стороны и снимает влияние порядка с разницы.
seq1["все A → все B"] --> bias1["перекос ложится только на одну сторону"]
alt1["чередовать A B A B или случайный порядок"] --> even1["перекос распределяется на обе стороны"]
even1 --> fair1["влияние порядка можно убрать из разницы"]
Рис. 11: Сгруппированные запуски тащат в сравнение ещё и перекос, поэтому чередуют или идут в случайном порядке.
От того, что измеряете, зависит смысл слова «быстро»
Если сжать «быстро» в одно число, обычно это ломается. Три характерных показателя, на которые стоит смотреть в Windows:
1. Wall-clock time (время по часам)
Время, которое ждёт пользователь. Это ближе всего к сквозному (end-to-end) ощущению, поэтому первым смотрят именно это значение.
В Windows для получения времени с высоким разрешением используют QueryPerformanceCounter (QPC).
В managed-коде база — семейство Stopwatch.
Смотреть миллисекунды через DateTime.Now уже слишком беспечно.
2. CPU time (пользовательское + время ядра)
Время, которое процесс реально использовал CPU; его получают через GetProcessTimes.
Это удобно, чтобы видеть вычислительную эффективность. Например, если wall-clock сократился, а CPU time не изменился, возможно сыграли кэш, I/O, ожидание или планирование.
3. Cycle count (число циклов CPU)
Через QueryProcessCycleTime можно получить число циклов CPU всего процесса.
Это тоже показатель CPU work, но он показывает другую сторону, чем wall-clock. Особенно удобен, когда нужно понять: «время ожидания то же, но стала ли легче вычислительная часть?»
flowchart TB
accTitle: Какую сторону показывает каждый из трёх показателей
accDescr: wall-clock time — время ожидания пользователя, CPU time — время CPU, которое процесс реально использовал, cycle count — тяжесть вычислительной части; смысл «быстро» читают только в сочетании.
spd1["Смотреть, что на самом деле значит «быстро»"] --> w1["wall-clock: время ожидания"]
spd1 --> u1["CPU time: реально использованное CPU-время"]
spd1 --> cy1["cycle: тяжесть вычислительной части"]
w1 -.-> mixr1["причину выводят из сочетания"]
Рис. 12: Не сжимать в одно число. Смысл скорости читают по сочетанию трёх показателей.
priority, affinity и NUMA — последнее средство
Иногда это влияет. Но если трогать это с самого начала только потому, что влияет, легко создать другое явление.
Сначала измерять в обычном режиме
Если разница появляется в состоянии по умолчанию, ценность есть уже в этой разнице.
Если сразу вставить /high или /affinity, вы вносите «условия, которых в реальной Windows не бывает».
flowchart TB
accTitle: priority и affinity — последнее средство
accDescr: Сначала измеряют в состоянии по умолчанию; если разница появляется, в ней уже есть ценность. Сразу фиксировать приоритет или affinity — внести условие, которого в реальной Windows не бывает, поэтому это делают в конце и с ясной целью.
def1["Сначала измерять в состоянии по умолчанию"] --> val1["если разница есть, в ней уже есть ценность"]
early1["сразу вставить /high или /affinity"] -.-> art1["внести условие, которого в реальности не бывает"]
val1 -->|"если понадобилось, задать цель"| lastr1["и зафиксировать как последнее средство"]
Рис. 13: Приоритет и affinity берут после измерения в состоянии по умолчанию и только с ясной целью.
Если всё же использовать — ясно задать цель
- /high: меньше мешать другим процессам
- /affinity: зафиксировать размещение по CPU для сравнения
- управление NUMA: на большой машине выровнять ещё и локальность памяти
Команда start в Windows умеет запускать процесс с priority class и affinity mask.
start "" /high /wait myapp.exe --bench case1.json
start "" /affinity F /high /wait myapp.exe --bench case1.json
Но /realtime не использовать
/realtime технически доступен, но лучше не использовать.
Это скорее не снимает шум, а создаёт другую аварию.
Рекомендуемая процедура измерений
С учётом всего выше — процедура, которой удобно пользоваться на практике.
Процедура ближе к лабораторной
- Зафиксировать объекты сравнения
- commit hash / build number
- версия compiler / runtime
- Debug / Release
- есть ли логи, assert, трассировка
- Зафиксировать условия машины
- Windows build
- версия BIOS / UEFI
- версия драйверов
- питание от сети
- температура в комнате, способ установки
- Зафиксировать условия питания
- выбрать Power mode
- записать Active power plan
- Перезагрузиться
- Подождать несколько минут перед бенчмарком
- При необходимости clean boot
- Добавить warm-up
- Чередовать A / B
- Обеспечить достаточное число запусков
- Оставить медиану, минимум, максимум, p95
- Сохранить raw data
- Если разница мала, снять ETW / WPR
Сколько раз прогонять
Для пункта 9, «обеспечить достаточное число запусков», тоже зададим ориентир. Это не статистически строгое решение, а практическая точка приземления.
| Что хотят увидеть | Ориентир числа запусков на одну версию |
|---|---|
| Смотреть только медиану и подтвердить крупную разницу (от 10%) | 10 |
| Утверждать разницу в несколько процентов и ещё видеть разброс | 30 |
| Читать ещё и p95 | 30 и больше. На 20 запусках p95 становится самим одним-двумя верхними значениями и напрямую принимает удар выбросов |
Время оценивают как время одного запуска × число запусков × число версий + warm-up. Если обработка на 30 секунд идёт по 30 раз для A и для B, с warm-up это около 35 минут. Если это нереально, лучше урезать объект измерения (вырезать только тяжёлый этап), чем резать число запусков.
Если неясно, где остановиться, простой способ: наращивать число запусков, следя за ходом медианы, и остановиться, когда добавление запусков её уже не двигает.
flowchart TB
accTitle: Где остановить число запусков
accDescr: Число запусков наращивают, следя за ходом медианы, и останавливаются, когда медиана уже не двигается даже после добавления запусков.
add2["Наращивать число запусков"] --> mdz1["смотреть ход медианы"]
mdz1 -->|"ещё двигается"| add2
mdz1 -->|"уже не двигается даже после добавления"| stop1["остановиться здесь"]
Рис. 14: Даже если число запусков заранее не зафиксировать, точку остановки можно взять там, где медиана устаканилась.
Что полезно записывать заранее — потом поможет
В CSV или JSON бенчмарка стоит оставить как минимум следующее.
timestamp,version,scenario,elapsed_ms,user_ms,kernel_ms,cycles,power_mode,power_plan,ac_or_dc,room_temp_c,notes
Если можно, удобно добавить ещё и такое.
cpu_package_temp_start_c,cpu_package_temp_end_c,affinity_mask,priority_class,windows_build,driver_version
В бенчмарке иногда важнее не сам факт измерения, а возможность потом интерпретировать результат.
Смотреть не только среднее, но и медиану с распределением
Среднее удобно, но в бенчмарке на Windows оно легко ломается. Достаточно одного сканирования Defender, одного уведомления или другого процесса, который ударил по SSD, — и среднее уезжает в сторону.
flowchart TB
accTitle: Среднее утягивает выброс
accDescr: Одиночный шум вроде сканирования Defender, уведомления или I/O другого процесса утягивает среднее, поэтому опираются на медиану и добавляют p95, p99 и min/max, чтобы читать по распределению.
once3["Один раз входит шум"] --> avg1["среднее уезжает в сторону"]
med2["опереться на медиану"] --> dist1["добавить ещё p95 / p99 и min / max"]
dist1 --> robust1["чтение устойчивее к выбросу"]
Рис. 15: Среднее ломается от одного шума, поэтому читают сочетанием медианы и распределения.
Рекомендуется такая комбинация:
- Медиана: смотреть её первой
- p95 / p99: проверить, не ухудшился ли хвост (tail)
- min / max: посмотреть, как отклоняется
- диаграмма размаха (box plot) или точечная (scatter): полезны, когда разница мала
Как читать, когда разница есть
Интерпретировать результат проще, глядя на сочетания.
Быстрее только wall-clock
Возможно улучшение I/O, времени ожидания, кэша или планирования.
Падают и CPU time, и cycle
Вероятно, стала легче сама реализация.
Медленно / быстро только в первый раз
Это разница cold / warm. Подозревают запуск, инициализацию, построение кэша, JIT.
С каждым следующим запуском всё медленнее
Подозревают тепло, throttling, давление памяти, фоновую активность.
flowchart TB
accTitle: Причину читают по рисунку разницы
accDescr: Если разница только в wall-clock, подозревают ожидание или I/O; если падает ещё и CPU time — более лёгкую реализацию; если отличается только первый запуск — cold и warm; если поздние запуски медленнее — тепло или фон.
pt2["Смотреть рисунок разницы"] -->|"только wall-clock"| c1a["ожидание / I/O"]
pt2 -->|"падает ещё CPU time"| c2a["реализация легче"]
pt2 -->|"только первый раз"| c3a["cold / warm"]
pt2 -->|"медленнее к концу"| c4a["тепло / фон"]
Рис. 16: Не сама разница, а рисунок, в котором она появляется, наводит на причину.
Доходить до «почему быстрее» через ETW / WPR
Когда разница мала или причину не прочитать, классический путь — перейти к инструментам Windows на базе ETW (Event Tracing for Windows).
Windows Performance Recorder (WPR) от Microsoft — инструмент записи на базе ETW, входит в Windows ADK.
Можно сразу снять CPU, I/O, context switch, ошибки страниц и другое.
Минимальный вариант выглядит так.
wpr -start CPU -filemode
REM Здесь выполняется бенчмарк
wpr -stop trace.etl
После открытия в WPA первые графики, на которые смотрят, обычно одни и те же.
| Что хотят увидеть | Какой график открыть | Как читать |
|---|---|---|
| В какой функции расходуется CPU | CPU Usage (Sampled) | Сортировать по Weight и сравнивать стеки A и B. Это sampling, поэтому короткая обработка вроде DPC / ISR часто не видна |
| Почему есть ожидание | CPU Usage (Precise) | Смотреть Ready-время, время ожидания и причину context switch. Разница ожидания lock или I/O проявляется здесь |
| Не затыкается ли из-за драйвера | DPC/ISR | Смотреть время по модулям. Если здесь много, разница изначально не на стороне приложения |
| Влияет ли диск | Disk Usage | Смотреть число и размер операций I/O и время обслуживания |
При сравнении базовый приём: снять по одной трассировке A и B на одном сценарии и положить рядом один и тот же график. По одной трассировке нельзя решить, «это медленно или нет».
На этом этапе можно перейти от «B быстрее на 3%» к «у B меньше ожидания lock, и ready time снизилось» «у A больше открытий файлов, поэтому cold start медленнее» — говорить уже с причиной.
flowchart TB
accTitle: От разницы только в числе к разнице с причиной
accDescr: Когда разница мала или причину не прочитать, в WPR снимают по одной трассировке A и B на одном сценарии и в WPA кладут рядом один и тот же график — тогда можно говорить с причиной, а не только с процентом.
small2["Разница мала / причину не прочитать"] --> tr1["снять трассировки A и B в WPR"]
tr1 --> cmp2["в WPA положить рядом один и тот же график"]
cmp2 --> rsn1["можно говорить с причиной"]
cmp2 -.-> onen1["одной трассировки недостаточно, чтобы решить, медленно ли это"]
Рис. 17: Когда доходят до ETW, «быстрее на X%» становится «почему быстрее».
Чеклист на одну страницу
В конце — в виде, который можно сразу вставить в инструкцию.
Зафиксировать
- Зафиксировал объект сравнения (commit hash / build number / Debug или Release / условия сборки вроде PGO / есть ли логи и assert)
- На ноутбуке подключил питание от сети
- Зафиксировал Power mode в приложении «Параметры»
- Проверил Active power plan через
powercfg /getactivescheme - Остановил уведомления. Остановил индексацию поиска и облачную синхронизацию
- При необходимости сделал clean boot
- Перезагрузился и подождал несколько минут, прежде чем начать
Выполнять
- Добавил warm-up
- Измерил отдельно cold (первый запуск) и warm (установившееся состояние)
- Прогнал A / B по очереди или в случайном порядке
- Задал число запусков и прогнал (ориентир — таблица выше)
Записывать
- Оставил raw data по одной строке на запуск (
elapsed_ms/user_ms/kernel_ms/cycles) - Оставил AC или DC, Power mode, GUID Power plan, Windows build, версию драйвера
- Оставил температуру в комнате и способ установки
- Записал и те условия, которые не фиксировал
Интерпретировать
- Посмотрел медиану. Не решал только по среднему
- Посмотрел хвост через p95 / p99
- Проверил выбросы через min / max
- Вывел причину из сочетания wall-clock / CPU time / cycle
- Если разница мала, дошёл до ETW / WPR
Итоги
Когда в Windows сравнивают разные версии программы, реально работает не эффектный трюк. Важна неброская практика, которая бьёт по воспроизводимости:
- Фиксировать и записывать AC / Power mode / Power plan
- Отделять cold и warm
- Чередовать A / B
- Смотреть медиану и распределение
- При необходимости clean boot
- Если разница мала, доходить до причины через ETW / WPR
И самое важное — вместе с результатом писать, что зафиксировали и что не фиксировали. Бенчмарк — это и сравнение скорости, и запись условий эксперимента.
Отчёт об ускорении без условий: другие не могут проверить, получится ли тот же результат. Остаются только числа, пути к воспроизведению нет. Наоборот, если условия записаны как следует, даже небольшая разница даёт результату настоящую ценность.
flowchart TB
accTitle: Запись условий задаёт ценность результата
accDescr: В отчёте об ускорении без условий остаются только числа, и другие не могут проверить; в отчёте с записанными условиями остаётся путь к воспроизведению, поэтому даже небольшая разница там ценна.
norec1["Отчёт без записи условий"] --> onlyn1["остаются только числа"]
onlyn1 --> norep1["другие не могут проверить"]
rec3["Отчёт с записанными условиями"] --> rep1["остаётся путь к воспроизведению"]
rep1 --> worth1["даже небольшая разница ценна"]
Рис. 18: Ценность бенчмарка сидит не столько в числах, сколько в записи того, что зафиксировали и что не фиксировали.
Справочные материалы
- Microsoft Support: Change the power mode for your Windows PC
- Microsoft Learn: Power Policy Settings
- Microsoft Learn: Customize the Windows performance power slider
- Microsoft Learn: Powercfg command-line options
- Microsoft Support: How to perform a clean boot in Windows
- Microsoft Support: Notifications and Do Not Disturb in Windows
- Microsoft Support: Search indexing in Windows
- Microsoft Learn: Configure custom exclusions for Microsoft Defender Antivirus
- Microsoft Support: Device Security in the Windows Security App
- Microsoft Learn: QueryPerformanceCounter function
- Microsoft Learn: Acquiring high-resolution time stamps
- Microsoft Learn: GetProcessTimes function
- Microsoft Learn: QueryProcessCycleTime function
- Microsoft Learn: start command
- Microsoft Learn: SetPriorityClass function
- Microsoft Learn: SetProcessAffinityMask function
- Microsoft Learn: Processor Groups
- Microsoft Learn: Windows Performance Recorder
- Microsoft Learn: WPR Command-Line Options
- Microsoft Learn: CPU Analysis in Windows Performance Analyzer - какой график что показывает.
- Microsoft Learn: Set the Default Power Plan - пример вывода
powercfg -LIST.
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Один и тот же 1 ГБ, а папка с фото копируется медленнее одного видео — почему?
Почему на Windows данные одного размера копируются с разной скоростью: число файлов, задержки SSD и NAS, сборка в ZIP, сравнение создания...
Что такое «аппаратно-ускоренное планирование GPU» в Windows — станет ли быстрее, если включить?
Наглядное введение в аппаратно-ускоренное планирование GPU (HAGS) в Windows для обычных пользователей. Как это устроено, когда включать и...
Что на самом деле делает быстрый запуск — почему «Завершение работы» в Windows не то же самое, что перезагрузка
Завершение работы Windows по умолчанию — гибридное: ядро и драйверы сохраняются в hiberfil.sys. Почему только перезагрузка их сбрасывает ...
Приложение ломается после сна — события питания и устойчивое восстановление
Открыли ноутбук — соединения бизнес-приложения уже мертвы. Так бывает, когда логика не рассчитана на сон. Разбираем цепочку уведомлений W...
WPR/WPA на практике: как разбирать «весь ПК тормозит» по всей системе
«Весь ПК тормозит» и «долго загружается» — проблемы, которые Диспетчер задач не объясняет. Их разбирают по общесистемной ETW-трассировке:...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Технические консультации и ревью дизайна
Тема хорошо стыкуется с технической консультацией и ревью архитектуры: от проектирования сравнения производительности и выравнивания условий измерения до разбора с ETW / WPR.
Расследование ошибок и причин
Когда между версиями появляется разница «быстрее / медленнее», разделение причин между питанием, теплом, фоновым шумом и разницей в реализации удобно вести как расследование сбоя и поиск первопричины.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Каковы основные причины разброса результатов бенчмарка в Windows?
- Факторы идут несколькими слоями: Power mode (режим питания) и Power plan (схема электропитания), тепловой режим, фоновые обновления, индексация поиска, антивирусное сканирование, приоритет и affinity, порядок запусков, состояние кэша. Даже на одной и той же машине с Windows, если эти условия не выровнены, по сути это уже другой эксперимент. Особенно на ноутбуке поведение сильно меняется в зависимости от питания от сети или от батареи, поэтому сравнивать нужно всегда при подключении к сети и записывать условия.
- Чем Power mode отличается от Power plan?
- Power mode — это переключение Best power efficiency / Balanced / Best performance в приложении «Параметры», в разделе Power & battery. Оно влияет на связанные с питанием настройки и на поведение PPM (Processor Power Management). Power plan — традиционная схема электропитания вроде Balanced или High performance, которую смотрят через powercfg. В Windows есть оба механизма, поэтому в результате бенчмарка нужно минимум записать три вещи: питание от сети или от батареи, какой Power mode, какой Active power plan.
- Если схема High performance не отображается — это поломка?
- Скорее всего нет. В документации Microsoft на устройствах с Modern Standby разрешены только Balanced или схемы, производные от Balanced. То есть отсутствие High performance на конкретной модели — нормальная особенность конструкции. Если элементы управления Power mode не удаётся изменить, возможно выбран custom power plan, поэтому быстрее всего сначала попробовать Balanced.
- В каком порядке запускать сравнение скорости версий A и B?
- Не стоит сначала прогнать все запуски A, а потом все B: перекос от тепла, кэша и фоновой активности ляжет только на одну сторону. Чередуйте A B A B или выполняйте заранее сгенерированный случайный порядок. Отдельно измеряйте холодный первый запуск и установившееся состояние после прогрева. Смотрите не только среднее, но и медиану, p95, минимум и максимум — так один выброс не утащит результат.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.