Как приручить дракона или заставляем локальные LLM и VirtualBox работать строго на P-cores в Windows 11

от автора

Сегодня мне хотелось бы поделиться решением проблемы, с которой гарантированно сталкиваются владельцы современных процессоров Intel (архитектуры Alder Lake, Raptor Lake и новее) под управлением Windows 11, если они пытаются “крутить” тяжелые локальные модели (LLM) или использовать виртуализацию.

Речь пойдет о принудительной изоляции «тяжелого» софта от энергоэффективных ядер (E-cores) и полной передаче вычислений производительным ядрам (P-cores) со стороны излишне навязчивой в этом плане Windows 11.

Кратко о сути проблемы на примере моего ноутбука.
В моём ноутбуке установлен процессор Intel Core i7-13850HX. У этого процессора вполне себе отличная конфигурация: 8 производительных ядер (16 потоков) и 12 энергоэффективных ядер (12 потоков). Всего 28 логических процессоров.

По задумке Intel и Microsoft, встроенный контроллер Thread Director должен сам понимать, какую задачу и на какие ядра (логические процессоры) ему нужно отправлять, но на практике, например, тот же гибридный режим работы (CPU + GPU) локальных нейросетей буквально вводит Windows 11 в полный ступор с “раcкидыванием” процессов на ядра.

Когда я, например, запускаю тяжелую локальную модель (Qwen 72B весом 47 ГБ) в LM Studio и настраиваю частичный перенос слоев на дискретную видеокарту (в моем случае это “скромная” RTX 2000 ADA 8GB), вычисления делятся между VRAM и оперативной памятью (RAM).

В такой ситуации работа LLM делится на две очевидные фазы:

  1. Prompt Processing (Prefill): Чтение запроса — видеокарта загружается на 100%.

  2. Token Generation (Decoding): Потоковая генерация текста по одному токену.

В фазе генерации видеокарта считает свои слои за считанные миллисекунды, после чего простаивает и ждёт, пока процессор и RAM досчитают “остаток” модели. В это же самое время Windows “видит” это «ожидание» и то, что окно LM Studio или фоновый Python-скрипт моего “моста” потеряли фокус и следом тут же “пугается” высокого TDP на ноутбуке в такие моменты и включает для них энергосбережение (Power Throttling с “зеленым листочком” в Диспетчере задач). А потом еще и принудительно “закидывает” потоки на медленные E-ядра!

Результат становится плачевным — скорость генерации падает, кулеры ноутбука начинают работать как «качели», страшно раздражая таким своим характером работы.

Такая же история происходит и с моим портативным VirtualBox.
Гостевые OS внутри виртуалки “не знают” о делении ядер на быстрые/медленные, и когда процессы виртуалок сама хостовая OS “раскидывает” между P и E ядрами, начинаются ощутимые задержки.

Изначально я пытался решить описанную проблему стандартной командой:

powercfg /powerthrottling disable /path “путь_к_exe”

Это хорошо помогает заблокировать падение частот, но имеет три больших недостатка:

  1. Утилита “powercfg” наотрез отказывается работать с путями на дисках, отличных от системного “C:” (а у меня Python-мост для работы с локальными моделями разворачивается на RAM-диске “W:” для максимальной скорости).

  2. Современные приложения на фреймворке Electron (такие как LM Studio) каждый раз “плодят” дочерние процессы (Renderers, GPU, Utility), которые игнорируют настройки родительского “.exe” и всё равно “сбегают” на E-ядра почти сразу после запуска.

  3. Настройки сбрасываются, если ваш RAM-диск пересоздается с нуля при загрузке системы.

Как же быть, подумал я, и придумал следующее. Конечно же, не без помощи тех самых моделей, которые и пытался ускорить 🙂

Оказалось, что надежным способом буквально “запереть” тяжелый софт на производительных ядрах, является использование так называемой системной маски сходства процессоров (“ProcessorAffinity”).

В частности, для процессора i7-13850HX в моём ноутбуке первые 16 логических потоков (“CPU 0” — “CPU 15”) — это всегда 8 быстрых физических P-ядер с Hyper-Threading. В шестнадцатеричной системе (Hex) маска для включения первых 16 потоков выглядит как “FFFF”. Запуск процессов с этой маской чётко блокирует им доступ к медленным E-ядрам (“CPU 16” — “CPU 27”).

Теперь, разобравшись со всем этим, осталось только всё удобно автоматизировать!

Ниже представлены два независимых готовых сценария автоматизации:

Сценарий 1: Запуск ИИ-станции (LM Studio + Python на RAM-диске)

Этот бат-файл запускается двойным кликом после того, как вы вручную открыли LM Studio и подгрузили тяжелую модель. Скрипт мгновенно находит все скрытые дочерние процессы LM Studio, “зажимает” их на быстрых ядрах через PowerShell, проверяет и разворачивает виртуальное окружение на RAM-диске “W:” (в моем случае) и запускает мой Python-мост со строгой привязкой к P-cores.

ПРИМЕЧАНИЕ: Сохраняйте “.bat” файл в кодировке UTF-8 без BOM, чтобы не сломать чтение команды @echo off и избежать нечитаемого текста.

@echo off:: Включаем поддержку UTF-8 для корректного вывода текстаchcp 65001 >nultitle ИИ-СТАНЦИЯ: LM Studio + Python P-Cores Onlymode con: cols=75 lines=14color 0A:: Переходим на RAM-дискcd /d "W:\AI_Bridge"echo ================================================================echo  [ИИ-СТРАЖ ЗАПУЩЕН] Настройка ресурсов процессора i7-13850HX...echo ================================================================echo.echo  [1/3] Перенаправление ВСЕХ процессов LM Studio на быстрые P-ядра...:: PowerShell находит все процессы LM Studio и зажимает их на ядрах 0-15 (маска 0xFFFF)powershell -Command "Get-Process -Name 'LM Studio' -ErrorAction SilentlyContinue | Where-Object { \(_.ProcessorAffinity -ne 0xFFFF } \vert{} ForEach-Object { try {\)_.ProcessorAffinity = 0xFFFF } catch { } }" 2>nulecho  [2/3] Проверка и подготовка виртуального окружения Python на RAM-диске...if not exist env (    python -m venv env    call env\Scripts\activate    pip install paramiko openai) else (    call env\Scripts\activate)echo  [3/3] Запуск скрипта qwen72_mod_a_FAST_CORES.py на быстрых P-ядрах...:: Запуск интерпретатора Python строго на первых 16 потокахstart "" /affinity FFFF "W:\AI_Bridge\env\Scripts\python.exe" "qwen72_mod_a_FAST_CORES.py"echo.echo ================================================================echo  Все процессы успешно запущены и изолированы от E-ядер!echo ================================================================timeout /t 3 >nul

После выполнения этот батник закрывается сам, а Python-мост и LM Studio остаются работать исключительно на быстрых ядрах.

Сценарий 2: Фоновый «страж» для Portable-VirtualBox.

С портативным VirtualBox ситуация немного сложнее. В моём случае лаунчер “VirtualBoxPortable.exe” запускает менеджер и тут же закрывается, а сами виртуальные машины (“VirtualBoxVM.exe” или “VBoxHeadless.exe”) я часто запускаю и останавливаю в разное время в разном сочетании, и ярлыки здесь просто не помогут.

Поэтому с помощью всё того же “Иван Иваныча” был написан по заданию автономный “скрипт-часовой”. Он запускается обычным двойным кликом (так как UAC у меня отключен, права админа подхватываются сразу). Скрипт превращается в бесконечный цикл, который раз в секунду сканирует систему. Как только вы запускаете любую виртуалку, он перехватывает её процесс прямо в момент «холодного» старта (до загрузки OS) и привязывает к быстрым ядрам:

@echo offchcp 65001 >nul:: Проверка прав администратораnet session >nul 2>&1if %errorLevel% neq 0 (    powershell -Command "Start-Process -FilePath '%0' -Verb RunAs"    exit /b)title СТРАЖ ЯДЕР: VirtualBox P-Cores Onlymode con: cols=65 lines=10color 0Aecho =========================================================echo  [СТРАЖ ЗАПУЩЕН] Права подтверждены. Окно можно свернуть.echo  Все новые и запущенные виртуалки переводятся на P-ядра.echo =========================================================echo.:LOOP:: Перехватываем процессы виртуалки на лету, игнорируя системные ошибки коротких потоковpowershell -Command "Get-Process -Name 'VBoxHeadless', 'VirtualBoxVM' -ErrorAction SilentlyContinue | Where-Object { \(_.ProcessorAffinity -ne 0xFFFF } \vert{} ForEach-Object { try {\)_.ProcessorAffinity = 0xFFFF } catch { } }" 2>nultimeout /t 1 >nulgoto LOOP

Этот батник вы просто сворачиваете в панель задач. Он потребляет 0% ресурсов процессора, но гарантирует максимальную производительность виртуализации из-за “раскидывания” всех процессов виртуалок на быстрые ядра.

Результаты эксперимента.

Их можно проверить визуально и, что называется — даже “на слух”:

  1. В Диспетчере задач на вкладке «Сведения» (Details) при клике правой кнопкой мыши на “python.exe”, “LM Studio.exe” или “VirtualBoxVM.exe” -> «Задать сходство» (Set Affinity), легко можно увидеть, что чекбоксы автоматически и строго стоят только на “CPU 0” — “CPU 15”. Медленные же ядра остаются “пустыми” для этих процессов!

  2. Акустический комфорт. Кулеры моего ноутбука перестали работать «рывками». Они выходят на стабильный, ровный рабочий гул, так как P-ядра больше не простаивают в ожидании потоков, застрявших на энергоэффективных ядрах.

  3. Общая стабильность. Практически исчезли микрофризы в виртуалках, а скорость генерации токенов локальной LLM стала стабильно высокой (насколько это вообще возможно для моего ноутбука) и без просадок.

При этом все 12 медленных E-ядер (“CPU 16” — “CPU 27”) остались свободными. Windows 11 отлично это “видит” и тут же “отгружает” на них свой системный фоновый мусор (апдейты, кэш браузера и т.п.), не мешая моей работе с “тяжелым” софтом.

Надеюсь, эта методика поможет выжать максимум из ваших гибридных процессоров, но помните, что перегрев и троттлинг также всегда должны быть под Вашим чутким контролем 😉

ссылка на оригинал статьи https://habr.com/ru/articles/1058624/