~/home

Процент загрузки CPU в Windows врёт при частичной нагрузке

· windows, производительность

TL;DR: Учёт загрузки по времени в Windows (диспетчер задач, GetThreadTimes, PDH % Processor Time) на частично нагруженном 8-ядерном 16-поточном CPU показывал до ~45% меньше, чем QueryThreadCycleTime. Чтобы понять, упираетесь ли вы в CPU, смотрите на загрузку GPU или GPU Busy в PresentMon.

В диспетчере задач игры ни разу не грузили мой 8-ядерный CPU больше чем на 30%, даже когда явно упирались в процессор. Я написал небольшой генератор нагрузки и сравнил то, что показывает Windows, с тем, что процессор делал на самом деле.

Тест

Запускаем N потоков, которые крутятся без единой блокировки. Для каждого потока раз в секунду сравниваем два числа:

  • время, которое ему засчитала Windows (GetThreadTimes, тот же источник, что использует диспетчер задач), и
  • реально отработанные такты (QueryThreadCycleTime), делённые на частоту.

Что получилось

  • 1 занятый поток: учёт по времени засчитал около 88% реального времени работы.
  • 8–12 потоков: падает примерно до 55%.
  • Заняты все 16 аппаратных потоков: оба способа показывают 100%.
  • Счётчик тактов всё время показывал 98–99%, и реальная производительность с ним согласна: 8 потоков сделали в 8,2 раза больше работы, чем один.

При 8 полностью загруженных потоках общесистемный «временной» показатель был 28,5%, хотя реально была занята примерно половина машины. Другой счётчик, «% Processor Utility», ошибается в обратную сторону и показывает 80–85%, потому что масштабирует результат по частоте буста относительно базовой. Причём в простое он показывал около 13%.

Что я смотрю вместо этого

На вопрос «упираюсь ли я в CPU?» процент загрузки CPU почти не отвечает. Загрузка GPU ниже потолка или GPU Busy из PresentMon в сравнении со временем кадра отвечают на него напрямую. Заодно проверил один сторонний диспетчер задач: он читает те же временные счётчики, так что и занижает так же.