Найти тему
OVERCLOCKERS.RU

Коротко о GPU Busy — новой метрике игровой производительности

Уже три года как тому назад читатели моего блога могли поближе познакомиться с очень важной метрикой игровой производительности, известной как время кадра, а так же узнать о свободной утилите PresentMon от Intel, способной эту величину измерять.

Сегодня Intel представила на суд общественности новую beta-версию утилиты PresentMon, в которой появилось много всего нового и интересного, например, вот такой красивенький конфигурируемый оверлей.

Оверлей — штука, безусловно, интересная и полезная, но мы обсудим другое не менее интересное и полезное нововведение, появившееся в новой версии PresentMon, а именно новую метрику производительности, названную разработчиками GPU Busy.

Для понимания сути этой метрики посмотрим на следующим слайд из видео с известного канала Gamers Nexus, в котором старший научный сотрудник Intel Том Петерсен (Tom Petersen) кратко объясняет смысл происходящего.

-2

Итак, каким же образом генерируется всякий новый игровой кадр?

Вначале центральный процессор, получив необходимую информацию о действиях игрока от устройств ввода, выполняет вычисления, связанные с игровой логикой и физикой, чтобы получить полное математическое описание состояния игрового мира, которое нужно отобразить на экране. Этот этап отражён на рисунке выше синим прямоугольником Game в строке CPU.

Затем центральный же процессор выполняет вычисления, которые преобразуют полученную актуальную математическую модель игрового мира в команды некоторого графического API, которые и приведут в конечном итоге к рендерингу нового кадра. Этот этап отражён на рисунке выше синим прямоугольником Render в строке CPU. В конце этого этапа вызывается команда графического API на отрисовку нового кадра. В API Direct3D, например, это вызов метода Present().

И вот здесь происходит много всего интересного. Несмотря на то, что все необходимые команды для отрисовки нового кадра уже собраны, передавать их напрямую в графический процессор бессмысленно, так как языка этих команд он попросту не понимает. Сначала управление передаётся библиотекам, реализующим API, которые переводят команды этого API в команды, понятные драйверу графического ускорителя. Затем драйвер графического ускорителя переводит эти ему одному понятные команды в инструкции, которые наконец-то может исполнять уже непосредственно графический процессор, и вот эти инструкции и передаются непосредственно графическому процессору. И всё это время, игра не может начать просчитывать следующий кадр на центральном процессоре, так как вынуждена ждать, пока будут выполнены все описанные выше преобразование команд графического API в инструкции графического процессора. Кроме того, перед отправкой инструкций графическому процессору может понадобиться подгрузить из основной памяти какие-то текстуры или скомпилировать какие-то шейдеры.

Весь этот этап подготовки инструкций и данных для графического процессора с точки зрения игры отражён на рисунке выше синим прямоугольником Wait в строке CPU. Обратите внимание, что центральный процессор в этот момент, конечно же, не находится в каком-то режиме ожидания, он вполне себе загружен, ведь именно он выполняет указанные выше преобразования команд графического API в инструкции графического процессора, а так же, возможно, загрузку текстур и компиляцию шейдеров. Но вот игра как раз вынуждена ждать окончания этого процесса, прежде чем начинать вычисления Game и Render уже для следующего кадра.

Как только последовательность инструкций графического процессора, соответствующая командам графического API, необходимым для рендеринга кадра, готова, она посылается графическому процессору. И тот уже попросту выполняет все необходимые для рендеринга кадра вычисления. Этот этап отражён на рисунке выше синим прямоугольником GPU Render в строке GPU.

Это, безусловно, очень упрощённая схема работы графического конвейера, но уже её достаточно для того, чтобы понять одну простую истину — время кадра, отсчитываемое по временным отсечкам вызова метода Present(), плохо отображает сколько времени на рендеринг потратил именно графический процессор. А ведь здесь возможны различные неприятные с точки зрения итоговой игровой производительности ситуации, в которых графический процессор по факту не виноват.

Например, возможно, что последовательный перевод команд графического API в команды драйвера, а затем в инструкции, понятные графическому процессору, будет занимать очень много процессорного времени. Такое, кстати, отнюдь не редкость. Это те самые пресловутые накладные расходы API и драйвера (API и driver overhead), о которых многие уже слышали и слышали не один раз. А возможно, в игре не лучшим образом реализован механизм подгрузки текстур или компиляции шейдеров "на лету", так что прямоугольник Wait растянется ещё сильнее.

-3

Все эти процессы могут сильно увеличить время кадра, но вины графического процессора в этом нет. И теперь появилась возможность определять такие неприятные ситуации, используя новую версию PresentMon, которая способна теперь измерять не только время кадра, но и время непосредственной работы графического процессора в ходе рендеринга кадра.

-4

Вот так, например, выглядел график времени кадра (голубой), посчитанного по временным отсечкам вызова метода Present(), и времени работы собственно графического процессора (жёлтый) в игре Overwatch 2 на системе с Core i5 13400F + Arc A750 и релизной версией драйверов Intel. В идеальном случае, как, например, в выделенной области в центре, эти графики почти повторяют друг друга. Да, время кадра, конечно же, чуть больше, так как в создании кадра принимает участие не только графический, но и центральный процессор, но больше оно лишь на некоторую незначительную и практически постоянную величину.

А вот в выделенной области слева ситуация, мягко скажем, неидеальная — графический процессор со своей задачей справился примерно так же быстро, как и в области в центре, но центральному процессору пришлось сделать заметно больше работы. И как итог время кадра на этом отрезке оказалось заметно выше. Конечно, не факт, что это произошло из-за того, что накладные расходы API или драйвера на этом участке оказались выше, или из-за того, что понадобилось загрузить какую-то текстуру или скомпилировать шейдер. Возможно, например, что в этот момент в игре произошло разрушение большого количества объектов виртуального мира, и время кадра оказалось большим из-за более долгого обсчёта физики. Но такие области, где наблюдается резкий контраст между временем кадра и временем работы графического процессора требует более детального изучения.

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

-5

Важно так же отметить, что Intel нарочно использует здесь не самый быстрый центральный процессор (Core i5 13400F), а не что-то более монструозное. И сделано это не только, и даже не столько, потому, что видеокарты уровня Arc A750 вряд ли можно будет встретить в реальных сборках с чем-то более мощным, чем Core i5, а потому, что топовые процессоры за счёт своей огромной вычислительной мощи банально способны справится со всеми задачами настолько быстро, что негативные эффекты от накладных расходов API и драйвера + не самые удачные решения по загрузке текстур и компиляции шейдеров "на лету" будут как-бы "скрадываться".

Возможна, впрочем, и обратная ситуация, когда попросту недостаточно мощный процессор не способен преодолеть указанные выше преграды на пути к меньшему времени кадра, а мощный графический процессор никак не способен повлиять на конечный результат. В общем, внезапно, во всём оказался важен баланс! И здесь мы уже находимся в шаге от вступления в секту "раскрывателей". Поэтому нам нужно быть предельно осторожными.😁Впрочем, теперь то у нас есть научный подход к этому вопросу и даже готовая утилита для необходимых замеров.

Итак, в хорошо сбалансированной системе хорошо оптимизированная игра, использующая API и драйвер с небольшими накладными расходами, должна демонстрировать картину производительности примерно как на графике выше. Да, время кадра (по определению) должно быть больше времени рендеринга кадра графическим процессором, но больше на небольшую и желательно постоянную величину.

📃 Читайте далее на сайте