УДК 004.415.25
В.Р. Газизов
магистрант, кафедра вычислительной техники, ФГБОУ ВПО «Санкт-Петербургский национально-исследовательский университет информационных технологий, механики и оптики»
ПРОГРАММНОЕ ПРОФИЛИРОВАНИЕ РАБОТЫ ГРАФИЧЕСКОГО ПРОЦЕССОРА
Аннотация. В статье рассмотрены программные методы профилирования работы графического процессора. Приложение для графического процессора базируются на интерфейсе программирования приложений OpenGL ES 2.0. Программный метод профилирования работы графического процессора даёт возможность разрабатывать эффективные приложения для графического процессора, абстрагируясь от его целевой архитектуры.
Ключевые слова: компьютерная графика, программное профилирование, графический процессор.
V.R. Gazizov, Saint-Petersburg national research university of information technologies, mechanics and optics
SOFTWARE PROFILING OT THE GPU
Abstract. The article describes the software profiling methods of the GPU. The application for the GPU based on the application programming interface OpenGL ES 2.0. Program profiling method of the GPU enables develop effective applications for GPU, abstracting from its target architecture.
Keywords: computer graphics, software profiling, GPU.
Разработка оптимальных приложений для графического процессора является итерационным процессом. Данный процесс включает в себя поиск «узкого места» в работе графического процессора (GPU) при исполнении определенного приложения (профилирование) и устранение данного «узкого места», изменяя вариант использования ресурсов GPU (оптимизация).
Производители мобильных графических процессоров предлагают свои собственные программные инструменты для выявления «узких мест», но для разработчика графического приложения использовать данные средства для множества потенциальных графических архитектур процессоров является затратным в материальном и временном плане. Исходя из того, что программная спецификация (для данной работы взята спецификация OpenGL ES 2.0), которой придерживаются производители графических процессоров и разработчики, выдвигает единую модель функционирования графического процессора, остается возможным с помощью программных тестов произвести профилирование графического процессора для конкретного приложения [3, с. 3].
Источниками, касательно программных способов профилирования, являются руководства по эффективному написанию графических приложений для популярных мобильных процессоров компаний PowerVR и Mali. Основываясь на том, что в большинстве случаев производитель графического процессора не раскрывает структурных и функциональных тонкостей графического процессора, данные способы рассматриваются как эвристические [4, 5].
Графический процессор представляет собой вычислительное устройство, состоящее из последовательности функциональных блоков, работающих по принципу конвейера. Объемные потоки данных поступают в конвейер частями, каждая из частей обрабатывается параллельно в определенный момент времени и на конкретной ступени конвейера.
На рисунке 1 показана структурная схема функциональных блоков графического процессора, изложенная в источнике [3].
Тонкими стрелками показан поток команд API между центральным процессором (CPU) и GPU. Жирными стрелками показан поток данных внутри GPU. Основной поток данных последовательно проходит через функциональные блоки GPU. Блоки, закрашенные серым цветом, программируются с помощью программ-шейдеров.
API OpenGL ES 2.0 разделяет функции переключения GPU в нужное состояние (включение
нужных программ-шейдеров, включение в качестве активной той или иной текстуры и т. д.) и функции передачи данных.
Рисунок 1 - Структурная схема функциональных блоков графического процессора
Исходные данные, который последовательно пройдут через все ступени графического конвейера, пропорционально их числу задают нагрузку на каждый блок. Оптимальный вариант использования графического процессора - создавать нагрузку равномерно для каждого вычислительного блока, так как производительность конвейера определяется производительностью его самого медленного блока.
Для простоты поиска «узкого места» работа графического конвейера анализируется от конечного блока к начальному блоку по ходу потока данных, так как каждый предыдущий блок влияет на следующий, а конечный блок не влияет ни на один из блоков. Рассматриваемый блок модифицируется программно (происходит упрощение задачи для данного блока и проверка общей производительности графической системы) [1].
Конечный блок в графическом конвейере, на который можно повлиять программно, -блок работы с буфером кадра. Результат визуализации графических данных пересылается в буфер кадра автоматически, а в дальнейшем они будут также переданы на дисплей устройства. Работа с буфером кадра необходима в случае, когда требуется получить сформированное изображение из буфера и обработать его повторно.
Данная операция нарушает параллелизм работы CPU и GPU, так как при её вызове со стороны CPU, GPU останавливает конвейерную обработку для доступа к буферу кадра до момента окончания считывания изображения. Данная операция привносит существенные задержки в работу GPU и её рекомендуется использовать как можно реже, или можно использовать некоторые альтернативные операции (использование виртуальных буферов), не затрагивающие буфер кадра [4, с. 29; 5, с. 8].
Итак, признаком «узкого места» могут быть функции по работе с буфером кадра, блокирующие параллельную работу GPU. Выявить их в программе и временно прекратить их использование для поиска "узкого места" не сложно. Если же не удалось выявить «узкое место» в бло-
ке буфера кадра, то необходимо перейти на предыдущий блок - блок работы операций над фрагментами. Данный блок предоставляет дополнительные операции над фрагментами (глубинный тест, функция наложения цветов, функции трафарета и т.д.) и вместе с основным блоком - фрагментным шейдером - определяет общие трудозатраты в числе операций для обработки каждого фрагмента получаемого изображения.
Проверить, является ли данный участок «узким местом» можно:
1) с помощью отключения фрагментных функций;
2) уменьшив размеры буфера кадра под хранения цвета фрагментов или под хранения глубины (для глубинного теста) - этим самым меньше сказывается ограничение пропускной способности памяти буфера кадра [1].
Следующий функциональный блок - блок обработки программы-шейдера для каждого фрагмента формируемого изображения. Операции, происходящие в данном блоке, ограничены производительностью памяти текстур и тактовой частотой данного блока [1]. Для выявления «узкого места» при работе с памятью текстур применяются следующие программные способы:
1) уменьшение размеров текстур (данный способ положительно влияет на кеширование текстур, так как с уменьшением размера больше текстур помещаются в кэш-памяти. При отсутствии кэш-памяти под текстуры, время выборки текстуры из памяти не зависит от размера текстуры, а зависит от площади области в пикселях, на которую накладывается текстура (это пропорционально числу обращений фрагментного шейдера к текстурной памяти);
2) изменение алгоритма фильтрации текстур на более простой (от алгоритма фильтрации зависит интенсивность обмена с памятью текстур), к примеру, при параметре фильтрации GL_LINEAR производится выборка нескольких соседних пикселей текстуры вместо одного, в отличие от GL_NEAREST.
Помимо выборки текстуры для фрагмента, в блоке фрагментного шейдера производится расчет цвета каждого фрагмента изображения (составляющие цвета и альфа-канал). Сложность программы-шейдера сказывается на быстродействии всей обработки фрагментов. «Узкое место» во фрагментном шейдере может быть выявлено:
1) путем изменения разрешения области отображения (данный способ уменьшает общее число фрагментов в изображении и, следовательно, уменьшает общее время просчета всех фрагментов);
2) путем изменение сложности программы-шейдера (программу-шейдер можно компилировать в процессе работы программы и заменить сложную программу на её более простую версию).
Рассмотрим следующий функциональный блок. Данные для блока по обработке фрагментов, использующего программу-шейдер для фрагментов, поступают из текстурной памяти и из блока растеризации. Одно из потенциальных узких мест в архитектурах GPU проявляется в блоке растеризации. Причиной «узкого места» в данном блоке является потребность в формировании большого числа фрагментов из геометрического описания примитивов (формирование пикселей по вершинам путем интерполяции) [2].
На блок растеризации нет возможности повлиять напрямую через API для работы с графикой, но можно обнаружить в нем «узкое место» косвенно - через тест - с применением программ-шейдеров с разной вычислительной сложностью, что создаёт разную задержку в вычислении.
На графике по оси х показано число примитивов, выводимых на сцене. Это число прямо пропорционально числу образуемых фрагментов; заметно, как с ростом числа фрагментов увеличивается время отображения кадра. Верхний график построен для фрагментной программы-шейдера с большей вычислительной сложностью, чем нижний; заметно, как уменьшается вклад сложности шей-дера (графики сближаются). Методом исключения это означает, что увеличивается время визуализации кадра за счет времени растеризации: время формирования фрагментов больше, чем время их обработки в блоке фрагментного шейдера. Блок растеризации становится «узким местом».
время 50 кадра, мс 40
30 20 10
О
число примитивов
О 50 100
Рисунок 2 - Обнаружение "узкого места" в блоке растеризации
Следующий функциональный блок с потенциальным «узким местом» (если ранее оно не было выявлено) находится в блоке вершинной обработки, и выяснить это помогут следующие программные тесты. Программу-шейдер можно компилировать в процессе работы программы и заменить сложную программу на её более простую версию.
Данные в блок вершинного шейдера попадают либо с внутренней памяти графического процессора, либо поступают непосредственно через шину данных под управлением центрального процессора. Здесь тоже не обошлось без потенциального «узкого места», выражающегося в ограничении пропускной способности шины между CPU и GPU. Центральный процессор по данной шине передает инструкции и данные.
Установить наличие «узкого места» можно, анализируя изменение времени формирования кадра изображения в случаях:
1) уменьшения числа переключений состояния процессора (команды по установке активной программы-шейдера, текстуры, включения/отключения блока обработки фрагментов и т.д.);
2) уменьшения числа вызовов команд отображения (glDrawElement, glDrawArray) путем увеличения выводимых объектов за одну команду отображения (к примеру, использование «вырожденных» примитивов для объединения объектов сцены в один набор примитивов);
3) уменьшения объема передаваемых данных путем индексации вершин, что позволяет использовать повторно координаты передаваемых вершин, а в ряде архитектур позволяет брать из кэш-памяти массивы передаваемых индексов [4, с. 69; 5, с. 12].
Если «узкое место» не было обнаружено в пределах блоков графического процессора или шины от CPU к GPU, то следует рассматривать CPU как «узкое место», а в дальнейшем необходимо проанализировать, на что тратятся ресурсы CPU [1].
Итак, в статье были рассмотрены способы программного профилирования работы графического процессора. Данные способы закреплены в руководствах по эффективному написанию приложений для графического процессора от ряда производителей графических устройств. Это позволяет применять данные способы при анализе «узких мест» и в дальнейшем провести требуемые операции оптимизации.
Список литературы:
1. Cem Cebenoyan GPU Gems. Graphics Pipeline Performance [Electronic resource]. URL: http://developer.nvidia.com/GPUGems/gpugems_ch28.html
2. Sebastien Domine Graphics Performance Optimization [Electronic resource]. URL: https://developer.nvidia.com/sites/default/files/akamai/gamedev/docs/Graphics_Performance_Optimiz ation.pdf
3. Aaftab Munshi, Dan Ginsburg, Dave Shreiner OpenGL ES 2.0 // Programming Guide Publication Date. 2008. August 3.
4. Mali GPU Version: 1.0 Application Optimization Guide, 2011 [Electronic resource]. URL: http://www.arm.com
5. Imagination Technologies. PowerVR. Performance recommendations [Electronic resource]. URL: http://www.imgtec.com