Как мы переносили современные игры на процессор Эльбрус-8С
Мы в Gaijin уже много лет работаем с самыми разными игровыми платформами — от ПК и мобильных устройств до Nintendo Switch, PlayStation 5 и Xbox Series X|S. На этот раз мы решили провести эксперимент — скомпилировали и запустили наши игры War Thunder, Enlisted и CRSED: F.O. A.D. на рабочей станции Эльбрус 801-РС, чтобы проверить, можно ли её превратить в развлекательную систему.
До этого на Эльбрусе компилировали и запускали только старые игры с открытым исходным кодом, так что давно уже назрели вопросы: насколько сложно перенести современные проекты, как они поведут себя и достаточно ли производительности процессора, чтобы поддерживать в них играбельную частоту кадров?
Игры, выбранные для тестирования, разработаны для PC и консолей, включая PlayStation 5 и Xbox Series X|S. Это онлайн-игры, где геймеры сражаются друг с другом, но наши эксперименты мы проводили исключительно в однопользовательском режиме — для оценки производительности этого вполне достаточно. Портирование проводилось двумя программистами в свободное от работы время, с нами на связи были разработчики ОС Эльбрус и разработчики, которые пишут и портируют программы для этого процессора (привет Рамилю из сообщества энтузиастов «e2k-dev team»).
Процесс компиляции не представляет собой что-то сложное, это не новая консоль, и здесь не надо писать свои драйверы. Наши игры запускаются на Линуксе, операционная система от МЦСТ похожа на Debian, а компилятор LCC умело прикидывается компилятором GCC.
Скриншот из игры War Thunder, по состоянию на май 2020 года, игра запущена на Эльбрус 801-РС
После того как удалось скомпилировать и запустить несколько простых приложений, мы собрали и запустили War Thunder c драйвером OpenGL 3. Запустить с Vulkan поначалу не смогли, так как компилятор шейдеров в драйвере вулкана зависал на коде больших шейдеров. В результате War Thunder выдавал с OpenGL примерно 25 кадров в секунду, а Enlisted и CRSED не работали, т.к. требовали Vulkan.
При этом больше всего тормозил рендер, так что мы надеялись получить приемлемый FPS, если в МЦСТ улучшат скорость работы драйверов Vulkan и OpenGL. Графический стек в операционной системе давно не обновлялся за ненадобностью, с системой поставлялась старая Mesa 17.2.8, этой версии хватало для запуска нетребовательных приложений, и даже каких-то игр, но для наших продуктов этого было недостаточно.
По нашей просьбе разработчики МЦСТ обновили графический стек, обновили Mesa до версии 2019 года (Mesa 19.3.5).
С обновлённым Vulkan количество кадров в секунду в игре War Thunder возросло в разы по сравнению с OpenGL и держалось в районе 60–70. А ещё, после того, как Vulkan привели в рабочее состояние, стало возможным запустить две другие наших игры — Enlisted и CRSED: F.O. A.D. Они после сборки показали 30 кадров в секунду.
Спустя некоторое время МЦСТ сами дополнительно обновили Mesa до версии 2020 года (Mesa 20.1.8). Это дало возможность использовать открытый компилятор шейдеров ACO (развиваемый компанией Valve), что значительно ускорило компиляцию шейдеров в Vulkan.
Всё это время мы экспериментировали на майской версии исходников игры CRSED: F.O. A.D, а когда обновились до более новых, в надежде улучшить быстродействие, нас ждал неприятный сюрприз: в игре получили 15 FPS.
Почему же в более ранней, майской версии, FPS был в два раза выше? Запустили профайлер, посмотрели — оказалось что время тратится на работу внутриигровых скриптов. Внутриигровые системы как раз всё лето переводили с С++ на daScript (это такой язык программирования, который может интерпретироваться и преобразовываться в C++ для Ahead-of-Time компиляции). Так вот, по умолчанию в не релизной сборке компиляция скриптов была отключена, на x86 это было не очень заметно, а вот для Эльбруса интерпретатор работал медленно из-за невозможности процессора предсказать переходы в ветвлениях.
После включения компиляции Ahead-of-Time для скриптов производительность вернулась к 30 кадрам в секунду. А после вынесения ботов и физики в отдельный процесс, средний FPS стал в районе 40 — то есть, уже достаточно, чтобы играть.
Потенциал для ускорения ещё есть. У компилятора LCC есть режим оптимизации с использованием профиля выполнения программы. На двух синтетических тестах он давал прирост скорости 4% для парсера выражений, и 270% для гранулярного синтеза звука. Но, к сожалению, мы так и не добрались попробовать его на играх.
Скриншот из игры Enlisted, игра запущена на Эльбрус 801-РС
А теперь факты и результаты тестов
Замеры проводились на компьютерах:
- Эльбрус 801-РС (32 GB DDR3, Эльбрус-8С 1.3 ГГц, SSD, AMD Radeon R9 380, Vulkan), ОС Эльбрус 6-rc3, компилятор LCC 1.25.09
- PC (16 GB DDR3, Intel i5–3570 3.4 ГГц, SSD, GeForce GTX 960, Vulkan), Windows 8.1, Clang 10.0.0
Видеокарты по тестам показывают ± одинаковые результаты, с разницей на пару процентов, поэтому будет считать их влияние для наших целей незначительным.
Объём кода который пришлось поменять в игровом движке Dagor 6 и в играх War Thunder, CRSED: F.O. A.D. и Enlisted в начале года (версия ядра 4.9, ОС Эльбрус 4.0-rc5, компилятор 1.23.19):
45 файлов, 450 строк.
Объём кода который пришлось поменять в октябре (версия ядра 5.4, ОС Эльбрус 6.0-rc3, компилятор 1.25.09):
25 файлов, 120 строк.
По-моему, 120 строк из 2,7 миллионов при переходе на новый компилятор и новую архитектуру — это неплохой результат. Уменьшение количества изменений связано с тем, что новый компилятор LCC стал поддерживать стандарт С++17, и больше не надо было переписывать фрагменты кода, которые его использовали.
Время компиляции игрового движка Dagor 6 и игры CRSED: F.O. A.D.
Компилировалось 4100 файлов, ~84 MB исходников:
Почему скорость компиляции ниже? При компиляции для архитектуры VLIW компилятор занимается принудительным дублированием кода, чтоб некоторые ветки программы частично выполнялись спекулятивно. Это позволяет сильнее загрузить исполнительные устройства процессора. Кроме замедлении скорости компиляции, это увеличивает размер кода.
Размер исполняемого файла:
Игры запускались со следующими настройками:
- War Thunder: оконный режим, разрешение 1908×1040, использовались настройки графики «Maximum», настройка «Tire/tracks marks» была выставлена в «None».
- Enlisted, CRSED: оконный режим, разрешение 1908×1040, использовались настройки графики по умолчанию, отключен «Global Illumination».
Количество кадров в секунду:
* — замер проводился сразу после загрузки, без движения техники.
** — на PC игра работает медленнее, чем на Эльбрусе. Это очень неожиданный результат; мы подозреваем что драйвер Vulkan для Windows работает медленнее, но подробные исследования ещё не проводили.
*** — в этом тесте боты, физика и рендер в одном процессе. В обычном режиме, физикой и ИИ занимается сервер.
Использование ресурсов в War Thunder в пробном выезде на танке:
Использование ресурсов в CRSED: F.O. A.D., одиночная игра с пятью ботами:
Видео
Что представлял из себя процесс портирования?
Про портирование уже есть несколько докладов и статей, например вот https://bit.ly/3nbnNfF, или вот https://bit.ly/3oL5G0q. Кратко опишу основные моменты, через которые пришлось пройти нам.
На компьютере с ОС Эльбрус мы собирали проект теми же скриптами сборки, которые используются для Linux. В системе есть псевдонимы для GCC и G++, которые указывают на компилятор LCC, и большая часть ключей компиляции GCC была понята компилятором LCC. За исключением нескольких ключей компиляции, в файле сборки исправлять ничего не пришлось.
Далее основная работа состояла в добавлении нового процессора в конфигурационные файлы проекта и библиотек. Вот например, как это выглядит для EASTL:
#elif defined(__e2k__)
#define EA_PROCESSOR_ELBRUS 1
#define EA_SYSTEM_LITTLE_ENDIAN 1
#define EA_PLATFORM_DESCRIPTION "OS Elbrus on E2K"
Вот ещё примеры патчей в библиотеки с открытым исходным кодом: https://www.altlinux.org/Эльбрус/upstream
Отдельно проверяли, не проверяется ли в коде наличие макроса __LCC__ (его определяет компилятор для Эльбруса LCC и компилятор языка С https://ru.wikipedia.org/wiki/LCC, вот такой вот конфликт). Некоторые библиотеки (например, c-ares) ошибочно полагали что они компилируются для 32-битного процессора с архитектурой Intel (пример патча для библиотеки curl: https://bit.ly/3oKh9h6).
Что касается платформозависимого кода, то обычно в библиотеках была реализация функций на чистом C/C++, и мы использовали её.
Итог
Мы удовлетворили свой интерес и запустили игры собранные под Эльбрус-8С. В игре War Thunder даже получили FPS в районе 60. В CRSED: F.O. A.D. и Enlisted количество кадров в секунду, по современным меркам с трудом можно назвать хорошим, но чтобы поиграть против ботов, 30–40 FPS вполне достаточно.
В общем, 8С уже можно считать подходящим для запуска современных игр, с интересом будем ждать следующий процессор — Эльбрус-8СВ.
Посмотреть как это работает на живом компьютере Эльбрус 801-РС можно в московском музее Яндекса https://yandex.ru/museum/, с 17 декабря и как минимум до конца января.
P.S.
Спасибо МЦСТ — они выдали нам на время экспериментов одну рабочую станцию.
Ещё спасибо Дмитрию из музея Яндекса, очень пригодились его знания про установку операционной системы.