Настройка 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. Сначала общая картина

Сначала общая картина выглядит так.

Код приложенияПланировщик WindowsПриоритеткогда поток скорее получит CPUAffinity / CPU Setsна каких CPU можно выполнятьQoS / EcoQoSпроизводительность или экономия энергииВыбор потока для выполненияВыбор логического процессораP-ядра / E-ядрапроизводительность или энергоэффективностьРежим питания / план питания / PPMчастота, буст, Core ParkingФактическая отзывчивостьвремя обработкинагреврасход батареивлияние на другие приложения

Важно, что эти вещи не независимы.

Подняли приоритет — поток скорее получит 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-приложении.

Нет / неизвестноДаДаНетДаНетДаНетДаНетСимптомымедленно, дрожит период, UI зависает, шумит вентиляторСначала записатьвремя обработки / максимум / загрузка CPU / состояние питания / сеть или батарея / целевой ПКCPU — главная причина?Проверить I/O, блокировки, БД, сеть, GC, GPU, драйверыубрать ожидания до приоритета и affinityСильная конкуренция за CPU с другими процессами?Рассмотреть приоритетно сузить областьHigh/Realtime постоянно не использоватьНагрузка сидит на конкретных CPU?Проверить affinity / CPU Setsне слишком ли жёсткая фиксациясмотрите ли P/E-ядра и NUMAПодозрительны частота или состояние питания?Проверить режим питания / план питания / PPMзаподозрить P-state / EPP / буст / Core ParkingФоновая работа мешает переднему плану?Рассмотреть EcoQoS / Efficiency Mode / понижение приоритетаувести неспешную работу на сторону экономии энергииПересмотреть алгоритм, степень параллелизма, очереди и устройство UI-потокаМенять по одному параметру и сравнивать A/BСмотреть не только среднее, но имаксимум, выбросы, нагрев, влияние на другие приложения

В этой схеме важно не крутить настройки с порога. Сначала записываете.

  • медленно ли постоянно
  • или медленно лишь иногда
  • питание от сети или от батареи
  • какой режим питания
  • не включён ли 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.

Справочные ссылки

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Как задать приоритет 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, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог