Настройка CPU для разработчика Windows-приложений: приоритет, affinity, P-ядра и E-ядра
· Обновлено: · Го Комура · Windows, Windows-приложения, CPU, Производительность, Приоритет, Affinity, P-ядра, E-ядра, Энергосбережение, EcoQoS
История изменений (5 обновлений, последнее 3 Sep 2026)
Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.
- Восстановлены четыре пункта заключения, оформленные блоком кода с отступом, и разделён пункт списка, в котором два утверждения были слиты в одно.
- Текст статьи исправлен, чтобы соответствовать японскому оригиналу.
- Переведён комментарий в примере EcoQoS. Утверждения статьи не менялись.
- Восстановлен список справочных ссылок. Утверждения статьи не менялись.
- Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
- Первая публикация
Цитирование статьи(DOI: 10.5281/zenodo.21619873)
Статья заархивирована на Zenodo. Ниже приведены DOI, который всегда ведёт к последней версии, и DOI, закреплённый за версией, которую вы читаете.
Го Комура (2026). Настройка CPU для разработчика Windows-приложений: приоритет, affinity, P-ядра и E-ядра. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21619873 https://comcomponent.com/ru/blog/2026/06/03/000-windows-app-cpu-priority-affinity-power/
- DOI (последняя версия)
- 10.5281/zenodo.21619873
- DOI (эта версия)
- 10.5281/zenodo.22279138
Производительность Windows-приложения кодом одним не определяется. Один и тот же .exe на разных ПК ощущается по-разному.
На одном ПК периодическая обработка стабильна.
На другом иногда опаздывает.
От сети всё нормально, на батарее почему-то медленно.
Приоритет в диспетчере задач подняли — быстрее почти не стало.
На P-ядра вроде направили, а время обработки всё ещё гуляет.
Наоборот: погнались за производительностью — вентилятор не умолкает, остальные приложения тяжелеют.
Разрабатывая Windows-приложения, как раз с такими вещами и сталкиваешься: кодом одним их не объяснить.
Тогда смотрите на эти четыре вещи.
| Что смотреть | Коротко |
|---|---|
| Приоритет | какой поток запустят раньше |
| Affinity | на каких CPU можно выполнять |
| P-ядра / E-ядра | это ядро ближе к производительности или к экономии энергии |
| Настройки питания | насколько CPU разрешено выкладываться |
В современной Windows сюда же подключаются EcoQoS и режим эффективности (Efficiency mode) в диспетчере задач.
То есть среда выполнения Windows-приложения — это не просто «быстрый CPU или медленный».
когда выполняется
где выполняется
на каком типе ядра выполняется
в каком состоянии производительности крутится CPU
считает ли ОС задачу «важной для производительности» или «достаточно экономии энергии»
Их сочетание и задаёт фактическую отзывчивость и время обработки.
В статье разбираем связи приоритета, affinity, P-ядер/E-ядер и настроек питания — то, что при разработке Windows-приложений легко упустить.
Код из статьи выложен на GitHub как готовый к сборке и запуску набор примеров (C#-библиотека и демо для приоритета и affinity, скрипты PowerShell, модульные тесты).
windows-app-cpu-priority-affinity-power - komurasoft-blog-samples (GitHub)
1. Сначала общая картина
Сначала общая картина выглядит так.
flowchart LR A["Код приложения"] --> B["Планировщик Windows"] P["Приоритет<br/>когда поток скорее получит CPU"] --> B AF["Affinity / CPU Sets<br/>на каких CPU можно выполнять"] --> B Q["QoS / EcoQoS<br/>производительность или экономия энергии"] --> B B --> C["Выбор потока для выполнения"] C --> D["Выбор логического процессора"] PE["P-ядра / E-ядра<br/>производительность или энергоэффективность"] --> D PM["Режим питания / план питания / PPM<br/>частота, буст, Core Parking"] --> D D --> R["Фактическая отзывчивость<br/>время обработки<br/>нагрев<br/>расход батареи<br/>влияние на другие приложения"]
Важно, что эти вещи не независимы.
Подняли приоритет — поток скорее получит CPU.
Но если сам CPU держат в сторону экономии энергии, быстрее может стать не так сильно, как ждали.
Сужаете CPU через affinity — миграция потоков может уменьшиться.
Но если сузили на энергоэффективные ядра или это не стыкуется с Core Parking и управлением питанием, станет хуже.
Направили на P-ядра — вычисления могут ускориться.
Но если всё свалить на высокопроизводительную сторону, вырастут нагрев, шум вентилятора, расход батареи и влияние на другие процессы.
Настройка производительности Windows-приложения — это не поиск «кнопки ускорения».
Какую работу нужно ускорить?
Какая может быть медленной?
Важнее отзывчивость на действия пользователя?
Или время, за которое закончится фон?
Насколько допустимы батарея и нагрев?
Это уже вопрос проектирования.
На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 25, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle
2. Приоритет задаёт, когда поток скорее получит CPU
В Windows, когда готовы несколько потоков, планировщик решает, какой из них следующим поставить на CPU. Здесь и работает приоритет.
В целом приоритет складывается из двух уровней.
класс приоритета процесса
+ относительный приоритет потока
= базовый приоритет потока
В Win32 API на стороне процесса есть SetPriorityClass, на стороне потока — SetThreadPriority.
Приоритет уже идущего процесса в PowerShell смотрят, например, так.
Get-Process -Id $PID | Select-Object Id, ProcessName, PriorityClass
Чтобы поднять приоритет текущего процесса PowerShell, так.
$p = Get-Process -Id $PID
$p.PriorityClass = "AboveNormal"
В C# это пишется так.
using System.Diagnostics;
using var process = Process.GetCurrentProcess();
process.PriorityClass = ProcessPriorityClass.AboveNormal;
Важно: приоритет — это не «настройка, которая ускоряет CPU». Он влияет на то, какой поток запустят первым, когда есть конкуренция.
Это не настройка частоты CPU.
Не настройка, которая выбирает P-ядро.
Не настройка, которая ускоряет I/O.
Не настройка, которая убирает ожидание блокировки или сети.
Поэтому «поднял приоритет, а быстрее не стало» бывает обычным делом. Если тормоза из-за пунктов ниже, повышение приоритета проблему по сути не снимает.
- ожидание дискового I/O
- ожидание сети
- ожидание ответа БД
- конкуренция за блокировки
- паузы GC
- блокировка UI-потока
- ожидание на стороне GPU или драйвера
- сканирование файлов антивирусом
- частота CPU удерживается в сторону экономии энергии
HIGH_PRIORITY_CLASS и REALTIME_PRIORITY_CLASS без нужды не берут.
Поток, который долго идёт с высоким приоритетом, неохотно отдаёт процессорное время другим.
Если это осталось внутри своего приложения — ещё куда ни шло, но можно ухудшить отзывчивость всей системы.
Приоритет похож на лекарство.
Где действует — действует.
Но наращивать дозу бессмысленно.
Что подумать до повышения приоритета
До того как поднимать приоритет, стоит задать себе такие вопросы.
| Вопрос | На что смотреть |
|---|---|
| Эта работа правда упирается в CPU? | загрузка CPU, ETW (Event Tracing for Windows — штатный механизм трассировки ОС), профилировщик |
| Не держит ли UI-поток? | отзывчивость UI, переход на async, устройство очереди |
| Короткий ли участок с высоким приоритетом? | поднять временно, по окончании вернуть |
| Не мешает ли другим приложениям? | ввод, печать, браузер, постоянно живущие программы |
| Не упрётся ли в права или политику у клиента? | права администратора, пользователь запуска, средства безопасности |
Для Windows-приложения важно не жить на максимальном приоритете, а отдавать приоритет нужной работе, в нужный момент и только в нужных пределах.
3. Affinity задаёт, на каких CPU можно выполнять
Если приоритет — это «когда поток скорее получит CPU», то affinity — «на каких CPU его можно выполнять».
В Windows процессу или потоку можно задать множество логических процессоров, на которых разрешено выполнение.
В Win32 API для процесса есть SetProcessAffinityMask, для потока — SetThreadAffinityMask.
Affinity процесса в PowerShell смотрят, например, так.
Get-Process -Id $PID | Select-Object Id, ProcessName, ProcessorAffinity
Для эксперимента ограничить текущий процесс PowerShell первыми четырьмя логическими процессорами можно так.
$p = Get-Process -Id $PID
$p.ProcessorAffinity = [IntPtr]0xF
0xF в двоичном виде — 1111.
То есть разрешены логические процессоры 0–3.
Это только пример для проверки.
Сужая affinity, иногда улучшают локальность кэша CPU и уменьшают дрожание периода.
С другой стороны, потоки, которые Windows могла бы увести на свободные CPU, оказываются зажаты в узком наборе.
Особенно осторожно в таких средах:
- смешаны P-ядра и E-ядра
- SMT/Hyper-Threading (Simultaneous Multi-Threading: один физический core показывают как несколько логических процессоров), поэтому соответствие логических процессоров физическим ядрам неочевидно
- NUMA (Non-Uniform Memory Access: расстояние до памяти с точки зрения CPU неоднородно)
- больше 64 логических процессоров, в игру входят Processor Group
- включён Core Parking
- сильное управление питанием со стороны OEM или BIOS
- приложение работает в виртуальной среде
Affinity жёстко говорит системе: «работай только на этих CPU».
Ограничение может стабилизировать.
Ошибка отрезает запасные варианты.
Сейчас есть ещё CPU Sets
Классическая маска affinity — довольно жёсткое ограничение.
В Windows есть ещё механизм CPU Sets.
CPU Sets — API, которым приложение мягче сообщает, на каких CPU оно хотело бы работать.
В описании Microsoft CPU Sets стоят как «soft»-affinity, совместимый с управлением питанием ОС.
Нужно жёстко закрепить CPU?
Или примерно сместить место выполнения, сотрудничая с управлением питанием и планированием ОС?
Эта разница важна.
Не пытайтесь закрыть всё старым SetProcessAffinityMask. В современном Windows-приложении в расчёт нужно брать и CPU Sets, и QoS.
4. P-ядра и E-ядра: у ядер тоже есть характер
В современных CPU не все ядра одинаковы по производительности и потреблению. Типичный пример — P-ядра и E-ядра: грубо, P-ядра ближе к производительности, E-ядра — к эффективности.
| Тип | В чём сильны |
|---|---|
| P-ядра | низкая задержка, высокая однопоточная производительность, тяжёлая работа на переднем плане |
| E-ядра | экономия энергии, фон, приём параллельной нагрузки |
Разработчику опасно бездумно решать, что «CPU 0–7 — P-ядра, 8–15 — E-ядра». Порядок номеров CPU может меняться от модели CPU, BIOS, версии Windows, прошивки, настроек OEM и виртуализации.
На стороне Windows в сведениях CPU Sets есть понятие EfficiencyClass.
Это значение показывает характеристику эффективности данного CPU Set в системе с разнородными процессорами. В документации Microsoft сказано: чем выше значение у CPU Set, тем более быстрый, но менее энергоэффективный процессор за ним стоит.
Если работаете с P-ядрами и E-ядрами, одних номеров CPU мало. Чтобы разобраться по делу, нужны такие наблюдения:
- смотреть
EfficiencyClassчерез API CPU Sets - смотреть, на каком CPU шёл поток, через Windows Performance Recorder / Analyzer (WPR / WPA — штатные инструменты, которые снимают и разбирают ETW-трассировку)
- смотреть тенденцию в отображении логических процессоров в диспетчере задач
- мерить время обработки на каждой конкретной машине
- сравнивать питание от сети и от батареи
- сравнивать разные режимы питания
P-ядра и E-ядра — не просто аппаратная спецификация. Фактическое место выполнения складывается вместе с планировщиком Windows, QoS и настройками питания.
5. Настройки питания определяют, насколько CPU разрешено выкладываться
На практике этот слой очень важен.
Приоритет — «какой поток запустят раньше».
Affinity — «на каких CPU можно выполнять».
P-ядра / E-ядра — «это ядро ближе к производительности или к экономии энергии».
А настройки питания относятся к тому,
на какой частоте и в каком энергетическом состоянии CPU вообще работает
Иными словами, бывает так.
Приоритет подняли.
На P-ядра направили.
Но если питание склоняется к экономии энергии,
CPU может не выйти на полную мощность.
Это очень «виндовая» история.
В Windows 11 режим питания выбирают в «Параметры» в разделе «Система > Питание и батарея».
Подписи зависят от среды и версии, но направление примерно такое.
| Режим питания | Направление |
|---|---|
| Наилучшая эффективность питания / Best power efficiency | батарея и экономия энергии |
| Сбалансированный / Balanced | баланс производительности и потребления |
| Наилучшая производительность / Best performance | приоритет производительности |
Плюс давно существуют планы питания Power Saver, Balanced, High Performance.
Balanced подстраивает производительность и потребление под нагрузку, High Performance легче выходит на максимум ценой потребления.
Снаружи настройки простые, сзади — параметры Processor Power Management, PPM.
6. P-state, C-state, буст, EPP
CPU не всегда крутится на максимальной частоте: у него есть состояния, которыми снижают потребление.
| Термин | Коротко |
|---|---|
| P-state | состояние производительности, которое меняет частоту и напряжение CPU |
| C-state | энергосберегающее состояние, которое в простое отключает часть функций CPU |
| Буст | переход в состояние выше номинала, когда условия позволяют |
| EPP | Energy Performance Preference. Предпочтение между производительностью и экономией энергии |
P-state снижает потребление, меняя частоту и напряжение CPU.
C-state в простое отключает часть функций и уходит в более глубокое энергосбережение.
Управление питанием Windows этими механизмами балансирует производительность и потребление.
Поэтому «приоритет высокий, а всё равно медленно» вполне бывает.
Поток выполняют предпочтительно.
Но частота CPU низкая.
Буст включается неохотно.
EPP смещён к экономии энергии.
Core Parking ограничивает доступные ядра.
На батарее вся ОС уходит в сторону экономии.
В таких случаях, глядя только на приоритет, до причины не дойти.
Особенно в периодической обработке, обработке изображений, управлении измерительными приборами, видео, звуке, захвате с USB-камеры, последовательной связи проблемой становится не только среднее время, но и «иногда опаздывает».
В среднем быстро.
Но раз из тысячи опаздывает.
Именно в этот раз буфер забивается.
UI зависает.
Синхронизация с оборудованием сбивается.
Для такого одной средней загрузки CPU мало.
Нужно вместе смотреть распределение времени обработки, максимум, выбросы, состояние питания, исполняющий CPU и фоновую нагрузку.
7. Core Parking влияет на число доступных ядер
В Windows есть Core Parking. Это управление, которое неиспользуемые логические процессоры уводит в покой.
При низкой загрузке часть ядер смещают в состояние с низким потреблением и тем самым экономят энергию.
В материалах Microsoft CPMinCores описан как параметр, который задаёт, какой минимальный процент логических процессоров в любой момент должен оставаться un-parked, то есть доступным.
При значении 100% алгоритм Core Parking отключается.
Проблема здесь — сочетание с affinity.
Через affinity ограничили: «работай на этой группе CPU».
Как эти ядра трактует управление питанием — отдельный вопрос.
В материалах для Windows Server тоже сказано: если активные потоки жёстко привязаны к части CPU внутри узла NUMA, это иногда не стыкуется с решениями Core Parking.
Как ход мысли это полезно и для клиентских ПК.
Affinity накладывает ограничение на планировщик.
Core Parking связан с тем, какие ядра управление питанием делает доступными.
Если смотреть на эти два слоя порознь, причину легко перепутать.
8. EcoQoS и Efficiency Mode: способ сказать, что задаче достаточно экономии энергии
Раньше настройка производительности Windows-приложения крутилась вокруг повышения и понижения приоритета и смены affinity. В современной Windows есть ещё одна ось — QoS.
QoS, Quality of Service, — способ указать потоку, насколько эта работа важна для производительности и насколько допустима экономия энергии.
В документации Microsoft приоритет планирования по-прежнему главный показатель, какой поток запустят следующим, а QoS может влиять на выбор ядра и на управление питанием процессора.
EcoQoS как раз для того, чтобы работу, где производительность не на первом месте, вести в сторону экономии энергии.
В C++ текущий поток переводят в EcoQoS, например, через SetThreadInformation и ThreadPowerThrottling.
#include <windows.h>
void EnableEcoQoSForCurrentThread()
{
THREAD_POWER_THROTTLING_STATE powerThrottling = {};
powerThrottling.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
powerThrottling.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
powerThrottling.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
SetThreadInformation(
GetCurrentThread(),
ThreadPowerThrottling,
&powerThrottling,
sizeof(powerThrottling));
}
Чтобы вернуть режим производительности, для того же объекта управления ставят StateMask в 0.
void DisableEcoQoSForCurrentThread()
{
THREAD_POWER_THROTTLING_STATE powerThrottling = {};
powerThrottling.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
powerThrottling.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
powerThrottling.StateMask = 0;
SetThreadInformation(
GetCurrentThread(),
ThreadPowerThrottling,
&powerThrottling,
sizeof(powerThrottling));
}
Из C# отдельного типа в библиотеке классов .NET для EcoQoS нет. Вызывают SetThreadInformation через P/Invoke. Ниже запись в расчёте на .NET 8.
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal static class EcoQos
{
// ThreadPowerThrottling из THREAD_INFORMATION_CLASS
private const int ThreadPowerThrottling = 3;
// THREAD_POWER_THROTTLING_CURRENT_VERSION
private const uint CurrentVersion = 1;
// THREAD_POWER_THROTTLING_EXECUTION_SPEED
private const uint ExecutionSpeed = 0x1;
[StructLayout(LayoutKind.Sequential)]
private struct ThreadPowerThrottlingState
{
public uint Version;
public uint ControlMask;
public uint StateMask;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetCurrentThread();
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetThreadInformation(
IntPtr hThread,
int threadInformationClass,
ref ThreadPowerThrottlingState threadInformation,
uint threadInformationSize);
/// <summary>Включает EcoQoS для текущего потока (false возвращает к режиму производительности).</summary>
public static void SetForCurrentThread(bool enabled)
{
var state = new ThreadPowerThrottlingState
{
Version = CurrentVersion,
ControlMask = ExecutionSpeed,
StateMask = enabled ? ExecutionSpeed : 0u,
};
var ok = SetThreadInformation(
GetCurrentThread(),
ThreadPowerThrottling,
ref state,
(uint)Marshal.SizeOf<ThreadPowerThrottlingState>());
if (!ok)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
Со стороны вызова это выглядит так. EcoQoS — настройка на поток ОС, поэтому безопаснее завести отдельный поток, включить там и выключить.
using System.Threading;
// RunBackgroundMaintenance — ваша «неспешная» работа
var worker = new Thread(() =>
{
EcoQos.SetForCurrentThread(true);
try
{
RunBackgroundMaintenance();
}
finally
{
// После использования обязательно вернуть
EcoQos.SetForCurrentThread(false);
}
})
{
IsBackground = true,
};
worker.Start();
Важно не вешать это напрямую на Task.Run и на поток из пула. Настраивается поток ОС, а не текущий Task. Если повесить EcoQoS на поток пула, он останется в стороне экономии энергии и когда пул отдаст его другой работе. При async / await продолжение может уехать на другой поток, и настройка начнёт или перестанет действовать вне задуманного участка.
EcoQoS — не функция «переведи всё на экономию». Она подходит, например, для такой работы:
- фоновая синхронизация
- построение индекса с низким приоритетом
- неспешный разбор логов
- обновление кэша, которое не связано напрямую с действиями пользователя
- обслуживание, которому достаточно закончиться позже
К таким задачам стоит относиться осторожно:
- работа, напрямую связанная с UI
- захват с камеры
- обработка звука
- работа, завязанная на цикл управления
- решение по результатам проверки на измерительном оборудовании
- экспорт, которого ждёт пользователь
- работа, которой нужен отклик, близкий к real-time
Efficiency mode в диспетчере задач связан с той же идеей.
В блоге Microsoft Performance Diagnostics сказано: при включении Efficiency mode базовый приоритет процесса опускают до Low, а QoS ставят в EcoQoS.
То есть Efficiency mode — не просто «значок экономии», а сочетание пониженного приоритета и EcoQoS, чтобы сохранить отзывчивость приложения на переднем плане и энергоэффективность.
С точки зрения разработчика это важно.
ОС можно сказать не только «эта работа должна закончиться быстро»,
но и «эта работа может идти, не мешая пользователю».
9. Схема разбора
Картина сложная, поэтому ниже схема, как разбирать тормоза и дрожание периода в Windows-приложении.
flowchart TD
A["Симптомы<br/>медленно, дрожит период, UI зависает, шумит вентилятор"] --> B["Сначала записать<br/>время обработки / максимум / загрузка CPU / состояние питания / сеть или батарея / целевой ПК"]
B --> C{"CPU — главная причина?"}
C -- "Нет / неизвестно" --> D["Проверить I/O, блокировки, БД, сеть, GC, GPU, драйверы<br/>убрать ожидания до приоритета и affinity"]
C -- "Да" --> E{"Сильная конкуренция за CPU с другими процессами?"}
E -- "Да" --> F["Рассмотреть приоритет<br/>но сузить область<br/>High/Realtime постоянно не использовать"]
E -- "Нет" --> G{"Нагрузка сидит на конкретных CPU?"}
G -- "Да" --> H["Проверить affinity / CPU Sets<br/>не слишком ли жёсткая фиксация<br/>смотрите ли P/E-ядра и NUMA"]
G -- "Нет" --> I{"Подозрительны частота или состояние питания?"}
I -- "Да" --> J["Проверить режим питания / план питания / PPM<br/>заподозрить P-state / EPP / буст / Core Parking"]
I -- "Нет" --> K{"Фоновая работа мешает переднему плану?"}
K -- "Да" --> L["Рассмотреть EcoQoS / Efficiency Mode / понижение приоритета<br/>увести неспешную работу на сторону экономии энергии"]
K -- "Нет" --> M["Пересмотреть алгоритм, степень параллелизма, очереди и устройство UI-потока"]
F --> N["Менять по одному параметру и сравнивать A/B"]
H --> N
J --> N
L --> N
M --> N
N --> O["Смотреть не только среднее, но и<br/>максимум, выбросы, нагрев, влияние на другие приложения"]
В этой схеме важно не крутить настройки с порога. Сначала записываете.
- медленно ли постоянно
- или медленно лишь иногда
- питание от сети или от батареи
- какой режим питания
- не включён ли Efficiency mode в диспетчере задач
- высока ли загрузка CPU
- поднимается ли частота
- какой поток ест CPU
- каково максимальное время обработки
- не участвуют ли другие постоянно живущие программы или антивирус
После этого меняете по одному.
Меняете приоритет.
Меняете affinity.
Меняете режим питания.
Включаете EcoQoS.
Выносите фоновую работу.
Ставите очередь.
Убираете с UI-потока.
Если менять несколько вещей сразу, не понять, что сработало.
10. Команды, которыми проверяют на месте
Когда Windows-приложение ведёт себя по-разному в разных средах, удобно сначала уметь снять состояние.
Сведения о CPU
Get-CimInstance Win32_Processor |
Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed
Активный план питания
powercfg /getactivescheme
Настройки управления питанием процессора
powercfg /q SCHEME_CURRENT SUB_PROCESSOR
Вывод длинный, но по нему видно минимум и максимум состояния процессора, EPP, буст и настройки, связанные с Core Parking.
Набор пунктов зависит от среды.
Диагностический отчёт по энергоэффективности
Запускают в терминале от имени администратора.
powercfg /energy
После измерения за фиксированное время выходит HTML-отчёт.
Это вход в драйверы, устройства, разрешение таймера, энергосбережение USB, то, что мешает сну.
Приоритет и affinity целевого процесса
Get-Process -Name MyApp |
Select-Object Id, ProcessName, PriorityClass, ProcessorAffinity
Проверка в диспетчере задач
На машине клиента PowerShell иногда не открыть. Если смотреть только GUI, идите в такие места. Подписи зависят от версии Windows, поэтому рядом даны английские имена.
| Что нужно увидеть | Действие |
|---|---|
| Приоритет процесса | Диспетчер задач → страница «Подробности» (Details) → правый щелчок по заголовку столбца → «Выбрать столбцы» → отметить «Базовый приоритет» (Base priority) |
| Изменить приоритет | На странице «Подробности» правый щелчок по процессу → «Задать приоритет» (Set priority) |
| Смотреть и менять affinity | На странице «Подробности» правый щелчок по процессу → «Задать сходство» (Set affinity) |
| Состояние режима эффективности | На странице «Процессы» (Processes) в столбце «Состояние» (Status) показывается «Режим эффективности». У родителя, у которого дочерние процессы в режиме эффективности, появляется значок листа |
| Включить режим эффективности | На странице «Процессы» выбрать процесс и нажать «Режим эффективности» на панели команд. Либо выбрать в контекстном меню |
| Нагрузка по логическим процессорам | Страница «Производительность» → «CPU» → правый щелчок по графику → «Изменить график» → «Логические процессоры» |
Режим эффективности нельзя применить к ключевым процессам Windows: если их остановить, страдает стабильность системы.
И это не просто подпись на экране. В блоге Microsoft Performance Diagnostics сказано, что режим эффективности опускает базовый приоритет процесса до Low и ставит QoS в EcoQoS. То есть с GUI разом включают две настройки из главы 8.
На странице «Подробности» диспетчера задач виден только приоритет процесса. Относительный приоритет потока и QoS по потокам там не показывают. Чтобы увидеть это, снимайте ETW через WPR / WPA.
Состояние производительности CPU
Имена счётчиков зависят от среды, но ориентироваться можно на такие Performance Counter.
Get-Counter '\Processor Information(_Total)\% Processor Performance'
Get-Counter '\Processor Information(_Total)\% Processor Utility'
Чтобы смотреть по делу, надёжнее снять ETW через Windows Performance Recorder (WPR) и Windows Performance Analyzer (WPA).
Так вместе видны дрожание периода, переключения контекста, исполняющий CPU, DPC/ISR (Deferred Procedure Call / Interrupt Service Routine — обработка прерывания в драйвере и её отложенное выполнение), дисковый I/O и изменения частоты CPU.
11. Для soft real-time нужно смотреть на всё сразу
Windows не является ОС реального времени в обычном смысле. Но от Windows-приложений на местах иногда ждут свойств, близких к real-time.
- брать кадры с USB-камеры с фиксированным периодом
- обмениваться с оборудованием по последовательной связи
- читать данные с измерительных приборов
- синхронизироваться с ПЛК и внешними устройствами
- обрабатывать звук или видео
- возвращать результат проверки за фиксированное время
- гонять тяжёлые вычисления, не замораживая UI
Для такой работы одной скорости кода мало.
Нужно устройство потоков.
Нужно устройство очередей.
Нужны логи.
Нужны тайм-ауты.
Нужен backpressure (механизм, которым специально снижают поток сверху, если низ не успевает обработать).
Нужно решить, что делать при опоздании: отбросить, ждать или повторить.
И поверх этого нужно смотреть приоритет, affinity, P-ядра/E-ядра и настройки питания.
Возьмём поток захвата с камеры.
Этот поток близко к действиям пользователя и к тому же периодический.
Поэтому EcoQoS на него вешать не следует.
Приоритет имеет смысл поднять на одну ступень и только на участок захвата. Но HIGH_PRIORITY_CLASS и выше постоянно использовать нельзя: пострадают UI и остальная работа.
Affinity фиксируют, только когда по замерам видно связь дрожания периода с миграцией между CPU. Если фиксировать, ядро выбирают не по номеру CPU, а по EfficiencyClass — на стороне P-ядер. Фиксация на E-ядрах даст обратный эффект.
Если режим питания склоняется к экономии энергии, задержки, которых не было от сети, вылезут на батарее. Поэтому в испытаниях производительности батарею нужно включать обязательно.
А сжатие старых логов?
Это типичная работа, которой пользователь не ждёт.
Тогда приоритет понижают.
Включают EcoQoS.
Запускают в простое.
Запускают только от сети.
Такое устройство добрее к приложению в целом.
Не делать «быстрой» всю работу, а разделить то, что должно быть быстрым, и то, что не должно мешать.
12. Базовые принципы проектирования
Когда в Windows-приложении трогают этот слой, принципов шесть.
1. Не фиксировать с порога
Лучше не фиксировать жёстко приоритет и affinity с самого начала.
Планировщик Windows во многих случаях справляется хорошо.
Лишние ограничения со стороны приложения иногда только ухудшают дело.
Сначала пишете как обычно.
Меряете.
Если вылезла проблема — строите гипотезу.
Меняете понемногу.
Снова меряете.
Именно в таком порядке.
2. Приоритет — на коротком участке
Высокий приоритет оставляют только на нужном отрезке.
Вместо того чтобы держать его постоянно, безопаснее
поднять непосредственно перед важной работой
и вернуть, когда она закончилась
3. Affinity рассматривают ближе к концу
Affinity — сильная настройка.
Она бывает полезна, когда подозревают дрожание периода или влияние миграции между CPU.
Но это не та настройка, с которой начинают.
Особенно если у клиентов разные ПК, жёсткая фиксация номеров CPU опасна.
4. P-ядра и E-ядра не «назначают», а наблюдают
Если хотите разделять P-ядра и E-ядра, сначала наблюдайте на живом железе.
Не фиксируйте по номеру CPU: смотрите CPU Sets, EfficiencyClass, ETW и замеры.
5. Тестируйте с учётом настроек питания
«На машине разработчика от сети и на высокой производительности быстро» — этого мало.
У клиента обычны такие состояния:
- ноутбук на батарее
- Best power efficiency
- Energy saver
- собственные утилиты экономии энергии от OEM
- настройки питания, зафиксированные корпоративной политикой
- тонкий ПК, который теряет производительность из-за нагрева
- рабочее место с большим числом постоянно живущих программ
В испытаниях производительности хотя бы эти условия стоит смотреть раздельно.
| Условие | На что смотреть |
|---|---|
| Сеть + Best performance | состояние, близкое к максимуму |
| Сеть + Balanced | типичная офисная работа |
| Батарея + Balanced | реальность ноутбука |
| Батарея + Best power efficiency | нижняя граница экономии энергии |
| Долгая непрерывная работа | нагрев, вентиляторы, thermal throttling |
| Одновременно с другими приложениями | соседство с браузером, Teams, Excel, антивирусом |
6. Для фона рассмотрите EcoQoS
Для работы, которая не бьёт прямо по пользовательскому опыту, иногда важнее не мешать, чем гнаться за скоростью.
Приложение, которое всё гоняет на высокой производительности, может быть быстрым.
Но оно мешает другой работе.
Раскручивает вентилятор ноутбука.
Тратит батарею.
В итоге им неудобно пользоваться.
В Windows-приложении качество — не только скорость, но и умение уживаться.
13. Частые заблуждения
Поднял приоритет — станет быстрее
Не обязательно.
Если причина в конкуренции за CPU, может сработать.
Если причина в ожидании I/O, ожидании блокировок, низкой частоте из-за экономии энергии или выполнении на E-ядрах, одного приоритета мало.
Зафиксировать на P-ядрах — всегда правильно
Не всегда.
P-ядра производительны, но растут нагрев и потребление.
Плюс возможна конкуренция с другой важной работой на переднем плане.
Важнее разделить работу, которую стоит направлять на P-ядра, и работу, которой хватит E-ядер.
Настройки питания — вкус пользователя, к приложению не относятся
Относятся.
Одно и то же приложение выполняется по-разному в зависимости от режима питания, плана питания, EPP, буста и Core Parking.
Особенно на ноутбуках поведение меняется между сетью и батареей.
Efficiency mode просто всё замедляет
Не просто замедляет.
За счёт пониженного приоритета и EcoQoS это механизм, который бережёт отзывчивость приложения на переднем плане и энергоэффективность.
Для неспешной фоновой работы его как раз стоит рассматривать всерьёз.
Windows нестабильна просто потому, что это Windows
Это тоже грубый взгляд.
Windows не является ОС реального времени.
Но если понимать планирование, управление питанием, QoS, измерения, логи и устройство потоков, на местах её можно сделать достаточно стабильной.
Проблема не в том, что «раз Windows — ничего не выйдет», а в том, что не смотрят, что происходит на каком слое.
14. Сначала спроектируйте журналирование, потом код
Такие проблемы иногда живут только у клиента. Поэтому полезно заранее оставить в приложении хотя бы минимум диагностики.
В диагностический лог имеет смысл писать такое.
- версия приложения
- версия Windows
- имя CPU
- число логических процессоров
- питание от сети или от батареи
- среднее, максимум и перцентили времени обработки
- число опозданий периода
- приоритет целевого потока
- приоритет процесса
- задан ли affinity
- задан ли EcoQoS
- план питания на старте
- сколько раз целевая работа ушла в тайм-аут
Когда клиент говорит «иногда медленно», а записей нет, остаётся гадать. Если есть логи, можно строить гипотезы.
медленно только на батарее
медленно только на конкретном ПК
медленно только сразу после запуска
медленно начиная с 30-й минуты
медленно только пока запущено другое приложение
выбросы появляются с фиксированным периодом
Если такие различия видны, проще отделить: приоритет, affinity, настройки питания, нагрев или другое ожидание.
15. Как это видит KomuraSoft
При разработке Windows-приложений одной аккуратной теории мало.
Работать на ПК клиента.
Работать на реальном терминале на месте.
Уживаться со старой периферией.
Работать в среде с антивирусом, принтерами и корпоративными политиками.
Не разваливаться на настройках питания ноутбука.
Там, где нужна производительность, её действительно выдавать.
Там, где спешить не нужно, не мешать пользователю.
Для этого Windows лучше не считать просто «чёрным ящиком ОС».
Windows думает, как гонять потоки.
Думает, на каком CPU их выполнять.
Балансирует потребление и производительность.
Работает с разнородными ядрами вроде P-ядер и E-ядер.
Пытается отличать приложение на переднем плане от фоновой работы.
Разработчику стоит не идти против этого, а в нужных местах сообщать намерение.
Эта работа заставляет пользователя ждать.
Эта работа может быть чуть медленнее.
Для этой работы важен период.
Эта работа может тихо идти в фоне.
Эта работа не должна мешать другим.
Такое проектирование опирается на понимание приоритета, affinity, QoS и настроек питания.
Что читать дальше
В этой статье разобраны настройки на стороне CPU. Если причина «медленно» лежит вне CPU, быстрее помогут следующие статьи.
| Симптом | Следующая статья |
|---|---|
| Непонятно, где уходит время | Как точно найти причину «медленной работы» с PerfView и dotnet-trace — практическое введение в анализ производительности .NET |
| Хотите сначала механизм записи в среде клиента | Введение в журнал событий Windows и ETW — как использовать стандартные механизмы ОС для логов бизнес-приложения |
| Подозреваете ожидание I/O или забитый пул потоков | Глубины ввода-вывода Windows (часть 3) — порты завершения ввода-вывода (IOCP) и пул потоков .NET |
| Память растёт, и из-за этого становится медленно | .NET: как отличить ожидание GC от утечки памяти |
| Зависает только UI | WPF и WinForms: async/await и поток UI |
16. Итог
Производительность Windows-приложения кодом одним не определяется.
Даже подняв приоритет, не получите ожидаемого, если affinity увело работу на E-ядра.
Даже направив на P-ядра, CPU не выдаст максимум, если режим питания склоняется к экономии энергии.
Жёсткий affinity без учёта CPU Sets и QoS отрезает запасные варианты управлению питанием и планировщику Windows.
Если всё свалить на высокопроизводительную сторону, вырастут нагрев, шум вентилятора, расход батареи и влияние на другие приложения.
В разработке Windows-приложений нужно проектировать не только скорость, но и отзывчивость, стабильность, потребление, нагрев и соседство с другими процессами.
И смотреть по-прежнему нужно на эти четыре вещи.
Приоритет
Affinity
P-ядра / E-ядра
Настройки энергосбережения
А на современной Windows к ним добавляются EcoQoS и Efficiency mode.
Справочные ссылки
- Полный набор примеров кода к этой статье (C# / PowerShell / модульные тесты) - komurasoft-blog-samples (GitHub)
- Scheduling Priorities - Microsoft Learn
- SetProcessAffinityMask function - Microsoft Learn
- SetThreadAffinityMask function - Microsoft Learn
- CPU Sets - Microsoft Learn
- SYSTEM_CPU_SET_INFORMATION structure - Microsoft Learn
- Change the power mode for your Windows PC - Microsoft Support
- Power Policy Settings - Microsoft Learn
- P-states and C-States - Microsoft Learn
- Processor power management options - Microsoft Learn
- CPMinCores - Microsoft Learn
- Quality of Service - Microsoft Learn
- SetThreadInformation function - Microsoft Learn
- Reduce Process Interference with Task Manager Efficiency Mode - Microsoft DevBlogs
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Один и тот же 1 ГБ, а папка с фото копируется медленнее одного видео — почему?
Почему на Windows данные одного размера копируются с разной скоростью: число файлов, задержки SSD и NAS, сборка в ZIP, сравнение создания...
Что такое «аппаратно-ускоренное планирование GPU» в Windows — станет ли быстрее, если включить?
Наглядное введение в аппаратно-ускоренное планирование GPU (HAGS) в Windows для обычных пользователей. Как это устроено, когда включать и...
WPR/WPA на практике: как разбирать «весь ПК тормозит» по всей системе
«Весь ПК тормозит» и «долго загружается» — проблемы, которые Диспетчер задач не объясняет. Их разбирают по общесистемной ETW-трассировке:...
Что продумать перед заказом разработки Windows-приложения
Перед заказом разработки Windows-приложения разберём, что стоит прояснить: доработка существующего ПО, интеграция с оборудованием, COM/Ac...
Планирование процессора в Windows: «Фоновые службы» и P-/E-ядра
Что реально меняет параметр «Фоновые службы» в Windows: квант времени, предпочтение foreground, срывы звука и QoS на CPU с P- и E-ядрами.
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Как задать приоритет CPU?
- Приоритет складывается из двух уровней: класса приоритета процесса и относительного приоритета потока. В Win32 API за процесс отвечает SetPriorityClass, за поток — SetThreadPriority. В PowerShell свойству PriorityClass объекта из Get-Process можно присвоить, например, "AboveNormal". В C# то же самое: ProcessPriorityClass.AboveNormal в PriorityClass у Process.GetCurrentProcess(). HIGH_PRIORITY_CLASS и REALTIME_PRIORITY_CLASS постоянно использовать не стоит: они ухудшают отзывчивость всей системы.
- Почему после повышения приоритета приложение не стало быстрее?
- Приоритет решает, какой поток запустят первым при конкуренции за CPU. Сам процессор он не ускоряет. Если тормоза из-за ожидания диска, сети, конкуренции за блокировки, пауз GC, блокировки UI-потока, сканирования антивирусом или из-за того, что настройки питания держат частоту CPU низкой, повышение приоритета проблему по сути не снимает. Сначала запишите распределение времени обработки, состояние питания и то, на каком CPU шла работа, и отделите причину.
- Что происходит, если задать EcoQoS через SetThreadInformation?
- Если в SetThreadInformation указать ThreadPowerThrottling и THREAD_POWER_THROTTLING_EXECUTION_SPEED, ОС получает сигнал рассматривать этот поток как EcoQoS (QoS со смещением к экономии энергии). QoS может влиять на выбор ядра и на управление питанием процессора, поэтому фоновую синхронизацию или неспешный разбор логов можно увести на сторону экономии, чтобы они не мешали приложению на переднем плане. К работе, напрямую связанной с UI, захвату с камеры и задачам с жёстким циклом управления стоит относиться осторожно. Чтобы вернуть режим производительности, поставьте StateMask в 0.
- Что такое CPMinCores в powercfg?
- CPMinCores — параметр питания Windows, связанный с Core Parking. Он задаёт, какой минимальный процент логических процессоров в любой момент должен оставаться un-parked, то есть доступным. При 100% алгоритм Core Parking отключается. Текущее значение смотрят от имени администратора командой powercfg /q SCHEME_CURRENT SUB_PROCESSOR. Если CPU ещё и сужен через affinity, решения Core Parking с этим иногда не стыкуются, поэтому оба параметра нужно смотреть вместе.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.