Повышение уровня игры с Burst 1.7

Последняя версия пакета Burst содержит несколько значительных улучшений как во времени итерации, так и в инспекторе Burst. В этом посте мы рассмотрим, что изменилось и как наша технология высокопроизводительного компилятора C# (HPC#) теперь может помочь вам повысить производительность на всех платформах с еще большей легкостью.
Хотя наш стек технологий DOTS использует Burst для обеспечения высокой оптимизации кода, Burst - это отдельный пакет, доступный в менеджере пакетов для Unity 2019.4 или более новой версии. Тысячи ваших проектов на всех основных настольных, консольных и мобильных платформах уже используют преимущества Burst.
В предыдущих выпусках Burst мы добились значительных успехов в улучшении повседневного опыта работы с Burst. В Burst 1.7 мы продолжили эту тенденцию, сосредоточившись на улучшении времени итерации. Что мы имеем в виду под временем итерации? Мы имеем в виду "внутренний цикл" разработки - вы вносите изменения в сценарий C#, переключаетесь обратно в редактор, ждете окончания компиляции сценария, ждете окончания компиляции Burst, а затем переходите в режим Play для проверки изменений.
В Burst 1.7 мы значительно сократили время ожидания Burst, когда вам нужно внести несколько изменений в код игры и протестировать его в режиме Play. Burst-компиляция теперь происходит раньше в конвейере (сразу после того, как конвейер компиляции сценариев закончил компиляцию сборок .NET), так что во многих случаях она завершается к тому времени, когда нужно запустить результирующий код. Вместо того чтобы компилировать каждую точку входа Burst отдельно, как это было в предыдущих версиях Burst, точки входа Burst (например, задание или указатель функции) теперь собираются вместе, чтобы повысить производительность компилятора и уменьшить количество библиотек, которые необходимо загрузить редактору.
Burst 1.7 также включает в себя значительное улучшение производительности прямых вызовов. Direct Call - это функция, которую мы добавили в Burst 1.5 и которая позволяет управляемому коду C# напрямую вызывать скомпилированный в Burst метод, не проходя через BurstCompiler.CompileFunctionPointer. Во время перезагрузки домена необходимо выполнить некоторую инициализацию, чтобы подключить методы прямого вызова, и в Burst 1.7 мы сделали эту инициализацию в 33 раза быстрее.
В качестве последнего замечания по теме времени итерации мы рассмотрели стоимость инициализации SharedStatic. SharedStatic - это механизм, позволяющий совместно использовать данные между управляемым C# и HPC#. В Burst 1.7 мы сделали инициализацию SharedStatic в 13 раз быстрее.
На следующих графиках показаны улучшения производительности Burst 1.7 по сравнению с Burst 1.6. Измерения проводились в рамках крупного проекта заказчика. Первый график ниже показывает время, отсчитанное с помощью секундомера (настоящего секундомера, а не System.Diagnostics.Stopwatch), наблюдающего за работой редактора, поэтому он должен отражать те улучшения, которые вы можете ожидать увидеть в повседневной работе.

Второй график ниже сосредоточен только на Burst, поэтому он исключает все остальное, что может происходить в редакторе. Для данного проекта и измененного файла Burst 1.7 быстрее, чем Burst 1.6, по всем трем временным параметрам:
- Холодный кэш - Burst еще не кэшировал результаты компиляции для кода в вашем проекте.
- Теплый кэш - Burst уже скомпилировал код в вашем проекте, и ему необходимо загрузить с диска кэшированные результаты компиляции.
- Изменить один файл - После изменения одного файла Burst проверяет, какие точки входа нужно перекомпилировать, и компилирует их. Обратите внимание, что количество улучшений в Burst 1.7, в общем случае, зависит от того , какой файл изменяется. Например, если вы измените метод, который используется всеми точками входа Burst, то разница между Burst 1.6 и Burst 1.7 будет меньше. В этом примере был изменен сам метод точки входа.

Burst Inspector (доступен через Jobs > Burst > Open Inspector...) - невероятно полезный инструмент для работы над оптимизацией. С помощью этого инструмента вы можете просмотреть ассемблерный код, который будет выполняться на целевом процессоре (процессорах). В Burst 1.7 мы добавили несколько востребованных функций. Скриншот говорит тысячу слов, поэтому без лишних слов:

Как видите, мы добавили маркеры ветвей, чтобы было проще визуализировать пути выполнения кода. Обратите внимание, что маркеры ветвей можно отключить с помощью флажка "Показывать поток ветвей", чтобы они не мешали вам, когда они не нужны. Особенно приятным аспектом этой функции является то, что вы можете щелкнуть на стрелке потока ветвей, и вы перейдете на другой конец стрелки, как в этом случае:
Пример щелчка по маркеру ветки для перехода к месту назначения ветки
Менее важные блоки разборки (например, директивы или константные данные) теперь автоматически сворачиваются, но их все равно можно переключить, когда вы захотите их просмотреть.
Также в Burst 1.7 появилась возможность выбрать только участок разборки и скопировать его.
Пример выбора и копирования определенного участка разборки
Вот список небольших, но не менее важных улучшений в Burst 1.7.
- API Arm Neon vst1* теперь полностью поддерживаются. Мы добавили эти API в Burst 1.6, но закрыли их за экспериментальным #define. В Burst 1.7 они больше не находятся под защитой #define и полностью поддерживаются.
- System.Span<T> и System.ReadOnlySpan<T> теперь поддерживаются в коде Bursted. Эти типы не допускаются в качестве аргументов точки входа.
- Burst теперь по умолчанию использует LLVM версии 12.0.0, что позволяет использовать последние улучшения оптимизации от проекта LLVM.
- Мы изменили конвейер оптимизации LLVM, чтобы разворачиватель циклов запускался исключительно после векторизатора циклов. Это улучшает кодеген во многих случаях.
- Мы заставили fmod и модуль с плавающей точкой использовать более быстрый алгоритм, чтобы повысить производительность.
- Burst теперь автоматически генерирует link.xml, чтобы избежать зачистки IL, приводящей к отсутствию символов во время выполнения из-за использования статических конструкторов.
- Мы улучшили производительность компилятора при выполнении копирования больших структур, обнаружив больше случаев, когда загрузка/хранение может быть безопасно преобразована в операцию перемещения в память.
- Мы внесли изменения в способ отображения таймингов при включении опции "Show Timings" в меню Burst. Очистив и представив информацию в более ясном виде.
Обратите внимание, что Burst 1.7 - это последняя версия, поддерживающая Unity 2019.4. Следующая версия Burst будет иметь минимальные требования Unity 2020.3. Если у вас есть какие-либо мысли, вопросы или вы просто хотите рассказать нам о том, что вы делаете с Burst, то, пожалуйста, не стесняйтесь оставить нам сообщение на форуме Burst.
