Профилирование проблем производительности в League of Legends
Перевод статьи из техблога Riot о профилировании производительности в League of Legends
Привет, меня зовут Тони Альбрехт и я работаю над League в качестве инженера. В этой статье мы собираемся посмотреть, как мы обнаруживаем, а затем фиксируем настоящие проблемы производительности. Те, которые ускользают от наших систем контроля качества и мониторинга и убегают на волю, чтобы поразить вас, Игрока.
Обнаружение проблем с производительностью в живой игре сложнее, чем кажется. Например, что такое плохая производительность? Это низкая средняя частота кадров? Некоторое количество медленных кадров? Какой-то другой показатель? Что представляет собой медленный кадр? На каком компьютере? С какой операционной системой? Какое другое программное обеспечение было запущено в фоновом режиме? Как только вы обнаруживаете проблему с производительностью, как она сообщается? Как вы собираете и разбираете журналы для игры, в которую ежедневно играют миллионы? И как вы воспроизводите состояние игры, которое вызвало проблему с производительностью, чтобы можно было все исправить?
Данная статья ответит на несколько из приведенных выше вопросов и познакомит вас с некоторыми из классных систем сбора данных о производительности, которые у нас есть для League.
По следу Свитхарт Ракана
League — это развивающийся продукт, и как таковые, ошибки будут проскальзывать. Эти ошибки могут быть в геймплее, дизайне или даже производительности (а иногда и сразу везде). Ошибки, которые приводят к сбою, обычно легче обнаружить и исправить, поскольку Bugsplat собирает игровые журналы и файлы дампа, которые мы можем использовать для воспроизведения состояния игры в момент сбоя. Затем мы можем проанализировать крэш, чтобы выяснить, что вызвало его, и исправить.
Поскольку ошибки производительности обычно не вызывают сбоев, у нас нет удобного метода их воспроизведения или даже идентификации. Несмотря на все наши усилия, направленные на уничтожение ошибок до того, как они убегут на волю, иногда мы узнаем о проблемах через службу поддержки игроков или даже Reddit. Эти анонимные сообщения, как правило, слишком расплывчаты, чтобы точно определить, что вызывает проблему производительности. И это снова подчеркивает важность надежного профилирования.
Например, «Я играл как Аатрокс и лагал в командных боях, помогите!» несет для нас мало пользы. Это Аатрокс вызывает проблему или один из других персонажей в игре? Связано ли это с вызовом определенной способности? Было ли это сочетание способностей? Или это проблема с компьютерными комплектующими у игрока? Операционной системой или сетью? Мы не можем это исправить, если не можем воспроизвести ошибку.
Даже профессионалам трудно определить причину замедления. В матче NA LCS в марте 2018 года Cloud 9 сообщил о значительном сокращении частоты кадров во время командного боя. Триггер замедления был зарегистрирован как ульт (самая сильная атака) Азира.
Как вы можете видеть, здесь многое происходит, но счетчик FPS определенно ниже, чем должен быть. Это было связано с ультом Азира? Или это было что-то еще? Счетчик FPS обманчив — он сообщает о средней частоте кадров за последние несколько секунд, поэтому причиной снижения частоты кадров не всгда является то, что вы видите на экране. На приведенном выше кадре уменьшение до 45fps происходит из-за того, что произошло за последние несколько секунд, поэтому оно может даже не отображаться на экране.
Если бы только был способ воспроизвести ту игру, чтобы мы могли ее профилировать …
Воспроизвести… воспроизвести… У нас есть файлы воспроизведения! Мы можем получить файл воспроизведения игры, если у нас есть ее идентификатор, а затем мы можем использовать файл, чтобы увидеть, можем ли мы воспроизвести проблему с производительностью. Приходится пройти несколько кругов. Воспроизвести игру можно только с той версией патча, на котором она была запущена первоначально. Кроме того, живые сборки не содержат весь наш код профилирования. Но с контролем версий мы можем легко создавать то, что нам нужно.
Повторные прогоны не совсем то же самое, что и исходный прогон. Время, затраченное на дешифрование самого файла воспроизведения, значительно отличается, и HUD отличается. Но в целом повтор достаточно похож, чтобы позволить нам находить общие ухудшения производительности. Стоит отметить, что игра, в отличие от игрового сервера, не детерминирована (ознакомьтесь с этой темой в серии Рика про детерминизм). Это означает, что при повторном воспроизведении ситуаций нам приходится получать немного разные результаты.
Повтор игры с Cloud9 позволил нам перейти к моменту описанного падения производительности. Затем мы смогли повторить точный командный бой, который вызвал замедление, и использовать инструменты для профилирования в игре, чтобы определить причину. Оказывается, это была система частиц. Изображение ниже содержит только частицы в сцене. Сможете угадать преступника?
Я облегчу вам задачу — вот только треугольники визуализированных частиц:
Да, я тоже не мог найти. Профилирование в игре подтвердило, что в то время было определенное снижение производительности. Кое-что заняло много времени для вычисления на CPU; это не связано с GPU. С помощью сборки Profile мы можем сохранить дамп трассировки, который загрузим в chrome://tracing для просмотра. Это показало следующее:
В предыдущей статье объясняется, как читать этот дамп трассировки.
Верхний график соответствует основной теме League. Нижний график — это поток моделирования частиц, где много работы с частицами происходит параллельно. Чем длиннее цветной блок функции, тем дольше идет ее выполнение. Причина снижения производительности очевидна. Замедление вызвал Rakan_Skin02_R_Rush_Trail – ульт Свитхарт Ракана (в темно-синем). Вопрос: почему?
Углубленная проверка эффекта показала, что след Ракана потребовал много ресурсов для интерполяции. В нем было много треугольников, что делало его гладким, но медленным для генерации. Уровень интерполяции был пропорционален скорости Ракана, поэтому чем быстрее тот двигался, тем больше интерполяции требовалось, и больше времени процессора. Мы изменили след и сделали его независимым от скорости Ракана. В итоге след выглядел почти идентичным, но создавался гораздо быстрее.
Мы должны были задать себе несколько вопросов здесь: как это ускользает от нашего тестирования? И что еще важнее: почему это не было замечено перед тестированием? Ответ на первый вопрос заключается в том, что мы должны были заметить. Но как я уже упоминал ранее, трудно точно определить, что именно вызывает замедление, и это ускользало от нашего контроля. Второй вопрос важен. Мы должны были знать, насколько дорого стоит эффект, прежде чем установили его в рабочей версии игры, но мы этого не сделали. И мы не знали, потому что у нас не было профилирования, встроенного в инструмент создания частиц, поэтому наши художники не могли измерить стоимость какого-либо конкретного эффекта. Это было второе, что мы исправили.
Потому что за производительность несут ответственность все.
Снижение производительности при шейдинге Суэйна
Чтобы исправить проблему с производительностью, мы должны сначала ее воспроизвести. Если мы не можем воспроизвести ее, мы не можем сравнить свою оптимизацию с предыдущим состоянием и измерить, лучше она или хуже. Чтобы воспроизвести проблему, нам нужны точные отчеты, а иногда аналогичный компьютер.
В версии 8.3 Riot получал сообщения об ухудшении производительности, когда в игре был Суэйн. Это произошло после переработки дизайна и геймплея, поэтому мы, естественно, предположили, что сделали что-то не так в процессе переделки Суэйна. Отчеты игроков были разнообразными: от абсолютно непонятных до определения точного триггера. Мы попытались воспроизвести случаи, которые звучали правдоподобно, но не повезло. Мы посмотрели на воронов Суэйна, его способности, его кожу и анимацию, но ничто из этого не ударяло по производительности сильно
После изучения нескольких наиболее подробных отчетов, полученных от игроков, мы заметили кое-какие общие комментарии:
- Игроки использовали недорогие компьютеры.
- Суэйн был в поле зрения, и игрок атаковал его.
Нам удалось воспроизвести проблемы производительности, запустив двух игровых клиентов и сервер на средней машине. Так GPU хватило сил увидеть проблему. Наведение указателя мыши на Суэйна в качестве противника привело к падению FPS. С воспроизведением мы смогли выяснить, что вызвало замедление, и перейти к фазе «исправь это».
Замедление вызывалось всякий раз, когда игрок наводил указатель мыши на Суэйна-врага, но не тогда, когда он играл за Суэйна. Разница здесь в том, что для ясности мы рисуем контур вокруг героя противоположного игрока. На рисунке ниже показано, как визуализируются контуры. Поскольку герой визуализируется в буфере основного кадра, его одноцветная версия также отображается вторичному буферу вне экрана с использованием нескольких целей визуализации (шаги 1 и 2). Затем одноцветная маска размывается (шаг 3).
Этот процесс протекает быстро на высокопроизводительных компьютерах, но при меньшей производительности он может быть довольно дорогостоящим (вот почему тени на них также дороже). Стоимость этого размытия рассчитывается на пиксель, поэтому чем больше пикселей размыты, тем дороже эффект. Чтобы свести к стоимость минимуму, мы используем ограничивающий прямоугольник (пурпурный), обозначаем границы героя и делаем размытие только внутри этой области. Затем мы используем размытую текстуру в буфере вне экрана, чтобы отобразить контур героя (шаг 4).
Проблема со Суэйном в данном случае заключалась в том, что его ограничивающий прямоугольник был слишком большой. Мы обнаружили это, воспроизведя игру с помощью инструмента анализа производительности графики (например, GPA от Intel), который позволил нам разбить сцену на отдельные команды рендеринга, а затем визуализировать их. Оказывается, мы размыли более 90% экрана, чтобы нарисовать контур, и это заняло очень много времени на машинах с медленными графическими процессорами.
Исправить проблему было просто: всего лишь уменьшить размер ограничивающего прямоугольника для Суэйна. Причина слишком большого ограничивающего контура в первую очередь заключалась в том, что очертания Суэйна были больше, чем у большинства персонажей. Нашей обычной ограничительной рамки по не хватало. Для компенсации мы применили к размеру рамки множитель. Мы не знали, какой по величине множитель делал ограничительный прямоугольник, и не было заметного замедления на компьютерах с высокими характеристиками, которые мы изначально использовали для сборки героя, или на более дешевых компьютерах, на которых мы его тестировали. Поэтому Суэйн получил массивный ограничительный прямоугольник. Данные о производительности важны. Но когда в редакторе четко видно, какие последствия несут те или иные изменения, это также может остановить проблемы производительности еще до их возникновения.
Заключение
Чтобы исправить проблему с производительностью, вы должны иметь возможность ее воспроизвести. Как видно из приведенных выше случаев, это может быть очень сложно. Некоторые случаи требуют определенных обстоятельств или происходят только в определенных конфигурациях оборудования. Надежные системы профилирования могут помочь нам изолировать эти проблемы, но они все равно пробираются в живые сборки. Когда это происходит, мы полагаемся на отчеты игроков, чтобы помочь выявить эти проблемы, но не всегда получаем полную картину. Повторы игр могут помочь нам воспроизвести проблему, но даже они не работают во всех случаях.
Мы повышаем контроль производительности и тестируем патч. Наша цель — поддерживать (и иногда улучшать) производительность, даже когда мы добавляем новый контент. Если вы играете в League of Legends, и вы заметили падение производительности, сообщите об этом разработчикам, но также постарайтесь быть максимально конкретными. Иногда нам помогают ваши догадки насчет наших проблем с производительностью.