2.2Аналитический обзор аппаратных средств обработки графической информации В рамках обзора аппаратных средств обработки графической информации необходимо рассмотреть два класса устройств: графические ускорители и графические дисплеи. Анализ графических ускорителей позволяет выявить те аппаратные возможности, которые могут быть пригодны для повышения эффективности методов обработки полутоновых растровых изображений. Анализ современных дисплеев проводится с целью выявления диапазона поддерживаемых ими разрешений и глубин передачи цвета. Эти параметры оказывают существенное влияние на дальнейший выбор методов визуализации изображений.
2.2.1Аналитический обзор аппаратных возможностей графических ускорителей Сегодня на рынке видеокарт, по большому счету, присутствуют всего две фирмы-производителя графических ускорителей. Это ATI, купленная компанией AMD, и NVidia. Эти компании являются лидерами в этом сегменте компьютерных комплектующих, а конкурентная борьба между ними ведется с переменным успехом.
Графические ускорители компании NVidia делятся на следующие классы [18]:
GeForce – решения для игроков и домашних компьютеров;
Quadro – решения для профессионалов, работающих с 2D и 3D приложениями;
Tesla – решения для кластерных вычислений;
Tegra – графические ускорители для мобильных устройств.
Аналогичная ситуация наблюдается и среди видеокарт фирмы AMD: графические ускорители Radeon HD ориентированы на настольные системы, серия Mobility Radeon HD предназначена для мобильных устройств, а класс видеокарт FirePro используется в специализированных рабочих станциях [20].
Так как целью данной НИР является создание программных средств обработки изображений, использующих только настольный персональный компьютер, то дальнейшему анализу будут подвергнуты только карты NVidia GeForce и AMD Radeon HD.
Несмотря на различия в производительности и особенностях устройства графических ускорителей конкурирующих компаний, их общая архитектура и процесс функционирования во многом одинаковы [21]. Следовательно, изучение общих принципов архитектуры и функционирования современных графических ускорителей является достаточным для анализа их возможностей по обработке графической информации.
Анализ архитектуры и процесса функционирования современных графических ускорителей Микроархитектура графического ускорителя (ГУ) построена совсем иначе, чем у обычных центральных процессоров (ЦП), и в ней изначально заложены определенные преимущества. Задачи графики предполагают независимую параллельную обработку данных, и ГУ изначально мультипоточен. Микроархитектура спроектирована так, чтобы эксплуатировать имеющееся в наличии большое количество нитей, требующих исполнения [19, 21].
ГУ состоит из нескольких десятков процессорных ядер, которые в терминологии NVIDIA называются Streaming Multiprocessor, а в терминологии ATI — SIMD Engine. Далее будем называть их минипроцессорами, потому что они исполняют несколько сотен программных нитей и обладают большей частью (но не всей) функциональности обычного ЦП.
Каждый минипроцессор имеет локальную память, размером от 16 до 64 KБ. Она имеет сходное с кэшем первого уровня обычного ЦП время доступа и выполняет аналогичные функции наибыстрейшей доставки данных к функциональным модулям. В ГУ локальная память служит для быстрого обмена данными между исполняющимися нитями. Одна из обычных схем ГУ-программы такова: в начале в локальную память загружаются данные из глобальной памяти видеокарты. Далее несколько сотен нитей работают с этими данными в локальной памяти и записывают результат в глобальную память, после чего тот передается в ЦП. В обязанность программиста входит написание инструкций загрузки и выгрузки данных из локальной памяти. По сути, это разбиение данных для параллельной обработки. Графический ускоритель поддерживает также инструкции атомарной записи/чтения в память, но они неэффективны и востребованы обычно на завершающем этапе для объединения результатов вычислений всех минипроцессоров.
Локальная память является общей для всех исполняющихся в минипроцессоре нитей, поэтому, например, в терминологии NVIDIA она даже называется «разделяемой», а термином «локальная память» обозначается прямо противоположное – некая персональная область отдельной нити в глобальной памяти, видимая и доступная только ей. Но кроме локальной памяти в минипроцессоре есть ещё одна область памяти, примерно в четыре раза бо́льшая по объему. Она разделена поровну между всеми исполняющимися нитями, это регистры для хранения переменных и промежуточных результатов вычислений. На каждую нить приходится несколько десятков регистров. Точное количество зависит от того, сколько нитей исполняет минипроцессор. Это количество очень важно, так как латентность глобальной памяти очень велика, сотни тактов, и в отсутствие кэшей негде хранить промежуточные результаты вычислений.
Каждый минипроцессор обладает большим количеством вычислительных модулей, но все они могут выполнять только одну и ту же инструкцию, с одним программным адресом. Операнды же при этом у каждой нити могут быть свои. Например, инструкция сложения содержимого двух регистров: она одновременно выполняется всеми вычислительными устройствами, но регистры берутся разные. Предполагается, что все нити программы, осуществляя параллельную обработку данных, в целом движутся параллельным курсом по коду программы. Таким образом, все вычислительные модули загружаются равномерно. А если нити из-за ветвлений в программе разошлись в своем пути исполнения кода, то происходит так называемая сериализация. Тогда используются не все вычислительные модули, так как нити подают на исполнение различные инструкции, а блок вычислительных модулей может исполнять, как было сказано выше, только инструкцию с одним адресом. И, разумеется, производительность при этом падает по отношению к максимальной.
Ещё одним преимуществом ГУ перед ЦП является то, что векторизация происходит полностью автоматически в отличие, например, от таких технологий как SSE или MMX. Теоретически, можно писать программы для графического ускорителя, не беря во внимание векторную природу исполняющих модулей, но скорость такой программы будет не очень высокой.
Важной особенностью программ для ГУ является то, что нити обрабатываются блоками фиксированного размера (32 нити для NVidia, 64 для AMD). NVidia называет этот блок нитей термином «warp», AMD использует название «волновой фронт». Таким образом, на 16 вычислительных устройствах «волновой фронт» длиной 64 нити обрабатывается за четыре такта.
В случае, если к некоторому моменту времени не все нити одинаково продвинулись в выполнении программы, то происходит замедление. В этом случае нити из одного волнового фронта находятся в различных местах программы. Они разбиваются на группы нитей, имеющих одинаковое значение номера инструкции. И по-прежнему выполняются в один момент времени только нити одной группы — все выполняют одинаковую инструкцию, но с различными операндами. В итоге один волновой фронт исполняется во столько раз медленней, на сколько групп он разбит, а количество нитей в группе значения не имеет. Даже если группа состоит всего из одной нити, все равно она будет выполняться столько же времени, сколько полный волновой фронт. Аппаратно это реализовано с помощью маскирования определенных нитей, то есть инструкции формально выполняются, но результаты их выполнения никуда не записываются и в дальнейшем не используются.
Хотя в каждый момент времени каждый минипроцессор выполняет инструкции, принадлежащие только одному волновому фронту, он имеет несколько десятков активных волновых фронтов в исполняемом пуле. Выполнив инструкции одного фронта, минипроцессор исполняет не следующую по очереди инструкцию нитей данного фронта, а инструкции какого-нибудь другого. Тот фронт может быть в совершенно другом месте программы, это не будет влиять на скорость, так как только внутри волнового фронта инструкции всех нитей обязаны быть одинаковыми для исполнения с полной скоростью.
Таким образом, учитывая, что каждый волновой фронт состоит из 32-64 нитей, минипроцессор имеет несколько сотен активных нитей, которые исполняются практически одновременно. Ниже будет показано, какие архитектурные преимущества даёт такое большое количество параллельных нитей, но сначала рассмотрим, какие ограничения есть у составляющих графический ускоритель минипроцессоров.
Главное, что в графическом ускорителе нет стека, где могли бы храниться параметры функций и локальные переменные. Из-за большого количества нитей для стека просто нет места на кристалле. Действительно, так как ГУ одновременно выполняет порядка 10000 нитей, при размере стека одной нити в 100 КБ совокупный объем составит 1 ГБ, что равно стандартному объему всей видеопамяти. Тем более нет никакой возможности поместить стек сколько-нибудь существенного размера в самом ядре ГУ. Например, если положить 1000 байт стека на нить, то только на один минипроцессор потребуется 1 МБ памяти, что почти в пять раз больше совокупного объема локальной памяти минипроцессора и памяти, отведенной на хранение регистров.
Поэтому в программе для ГУ нет возможности организовать рекурсию. Все функции непосредственно подставляются в код при компиляции программы. Это ограничивает область применения графических ускорителей задачами вычислительного типа. Иногда можно использовать ограниченную эмуляцию стека с использованием глобальной памяти для рекурсивных алгоритмов с известной небольшой глубиной итераций, но это нетипичное применение ГУ. Для этого необходимо специально разрабатывать алгоритм, исследовать возможность его реализации без гарантии успешного ускорения по сравнению с ЦП.
Таким образом, ГУ представляется в роли вычислительного сопроцессора, в который загружаются данные, они обрабатываются некоторым алгоритмом, и выдается результат.
Основой высокой скорости вычислений на графическом ускорителе является высокая многопоточность. Большое количество активных нитей позволяет отчасти скрыть большую латентность расположенной отдельно глобальной видеопамяти, составляющую порядка 500 тактов. Особенно хорошо она нивелируется для кода с высокой плотностью арифметических операций. Таким образом, не требуется дорогостоящая с точки зрения транзисторов иерархия кэшей L1-L2-L3. Вместо неё на кристалле можно разместить множество вычислительных модулей, обеспечив выдающуюся арифметическую производительность.
Но кроме латентности глобальной памяти в вычислительном устройстве существует ещё множество латентностей, которые надо скрыть. Это латентность передачи данных внутри кристалла от вычислительных устройств к кэшу первого уровня, то есть локальной памяти GPU, и к регистрам, а также кэшу инструкций. Регистровый файл, как и локальная память, расположены отдельно от функциональных модулей, и скорость доступа к ним составляет примерно полтора десятка тактов. И опять-таки большое количество нитей, активных волновых фронтов позволяет эффективно скрыть эту латентность. Причем общая полоса пропускания доступа к локальной памяти всего ГУ, с учетом количества составляющих его минипроцессоров, значительно больше, чем полоса пропускания доступа к кэшу первого уровня у современных ЦП. ГУ может переработать значительно больше данных в единицу времени.
Можно сразу сказать, что если ГУ не будет обеспечен большим количеством параллельных нитей, то у него будет почти нулевая производительность, потому что он будет работать с тем же темпом, как будто полностью загружен, а выполнять гораздо меньший объем работы. Например, пусть вместо 10000 нитей останется всего одна: производительность упадет примерно в тысячу раз, ибо не только не все блоки будут загружены, но и скажутся все латентности.
Проблема сокрытия латентностей остра и для современных высокочастотных ЦП, для её устранения используются различные способы — глубокая конвейеризация, внеочередное исполнение инструкций. Для этого требуются сложные планировщики исполнения инструкций, различные буферы и т. п., что занимает место на кристалле. Это все требуется для наилучшей производительности в однопоточном режиме.
Но для ГУ все это не нужно, так как он архитектурно быстрее для вычислительных задач с большим количеством потоков. Графический ускоритель изначально был приспособлен для оптимального исполнения шейдерных программ для пикселей треугольников, которые, очевидно, независимы и могут исполняться параллельно. И из этого состояния он эволюционировал путем добавления различных возможностей (локальной памяти и адресуемого доступа к видеопамяти, а также усложнения набора инструкций) в весьма мощное вычислительное устройство, которое все же может быть эффективно применено только для алгоритмов, допускающих высокопараллельную реализацию с использованием ограниченного объема локальной памяти.
Анализ технических характеристик современных графических ускорителей В предыдущем пункте была рассмотрена архитектура современных графических ускорителей. Представление о ней является основой создания программ для ГУ. Анализ технических характеристик современных видеокарт позволит получить представление об ограничениях, накладываемых на эти программы. Например, если общий объём видеопамяти некоторого графического ускорителя равен 256 МБ, то не имеет смысла загружать текстуру большего размера, так как такая операция приведёт к ошибке. Другим примером является максимальное разрешение дисплея, поддерживаемого видеокартой. Зная его, можно делать предположения о максимальном количестве пикселей, интенсивность которых нужно рассчитать за один кадр визуализации. Это значение необходимо учитывать для создания эффективного алгоритма визуализации.
Так как технические характеристики видеоадаптеров представляют интерес с точки зрения определения ограничений, то для анализа нужно взять наиболее передовые графические ускорители. В настоящее время ими являются NVidia GeForce GTX 580 [18] и AMD Radeon HD 6970 [20]. Сравнение характеристик указанных графических ускорителей приведено в таблице 1 [22, 23].
Таблица 1 – Технические характеристики графических ускорителей
Параметр
| NVidia GeForce GTX 580
| AMD Radeon HD 6970
| Число транзисторов
| 3 млрд
| 2,64 млрд
| Разрядность шины памяти
| 384 бит
| 256 бит
| Тип памяти
| GDDR5
| GDDR5
| Частота ядра
| 772 МГц
| 880 МГц
| Количество минипроцессоров
| 16
| 24
| Количество скалярных АЛУ
| 512
| 1536
| Количество блоков текстурной адресации
| 64
| 96
| Объём памяти
| 1536 МБ
| 2048 МБ
| Порты вывода
| 2 Dual DVI + HDMI + DP
| 2 Dual DVI + HDMI + DP
| Максимальное разрешении 2D/3D
| 2560x1600
| 2560x1600
| Поддержка вычислений общего назначения
| DirectCompute11, NVidia PhysX, CUDA, CUDA C++, OpenCL 1.0
| ATI Stream, OpenCL 1.1, DirectCompute 11
| На основании анализа таблицы 1 можно сделать следующие выводы. Во-первых, в соответствии с приведённым в подразделе 1.1 определением, минимальный объём памяти, необходимый для хранения полутонового растрового изображения большого размера равен 4 мегапикселя × 8 бит на пиксель 4 МБ, следовательно, объём видеопамяти современных графических ускорителей на несколько порядков превосходит минимальный объём, необходимый для хранения одного полутонового растрового изображения большого размера. Этот факт существенно упрощает одновременную визуализацию нескольких изображений – все они могут быть загружены в видеопамять как текстуры, что обеспечивает высокую скорость их отображения.
Во-вторых, максимальное поддерживаемое разрешение составляет 2560 · 1600 4 мегапикселя. Следовательно, при разработке алгоритма визуализации важно учитывать, что за один кадр визуализации необходимо рассчитывать интенсивность не более 4 миллионов пикселей.
Наконец, при реализации методов обработки изображений с использованием графического ускорителя можно использовать самые последние версии специализированных языков (DirectCompute 11, OpenCL 1.1, CUDA C++), так как они уже реализованы в рассматриваемых чипах.
2.2.2Аналитический обзор современных графических дисплеев Анализ современных дисплеев необходим для выявления двух параметров, оказывающих влияние на алгоритм визуализации изображений: максимального разрешения и максимальной глубины цветопередачи. Знание первого параметра необходимо для определения максимального количества пикселей, обрабатываемых за один кадр визуализации. Максимальная глубина цветопередачи поможет определить максимальное количество оттенков серого, которое могут отображать современные дисплеи.
Выше уже было определено, что максимальный размер изображения, создаваемого передовыми графическими ускорителями, равен 4 мегапикселям. Если максимальное разрешение современных мониторов меньше этого значения, то именно его необходимо будет принять за верхнюю границу числа пикселей, интенсивность которых рассчитывается за один кадр визуализации.
Анализ современных дисплеев лидирующих производителей показывает [24-26], что большинство мониторов для персональных компьютеров имеет разрешение 1920x1080. Однако фирма Dell [26] имеет модель Dell UltraSharp 3011 для персональных компьютеров с диагональю 30 дюймов и разрешением 2560x1600. Таким образом, максимальное разрешение современных графических дисплеев совпадает с аналогичным параметром графических ускорителей. Следовательно, оценка максимального количества обрабатываемых за один кадр визуализации пикселей остаётся неизменной.
Кроме того, анализ показывает, что все современные дисплеи работают в цветовом пространстве RGB [1] и используют метод кодирования TrueColor, в котором для хранения красной, зелёной и синей составляющей цвета отводится по 8 бит [24-26]. Это значит, что современные дисплеи способны отображать максимум 28=256 градаций серого. Следовательно, если цветовая глубина визуализируемого изображения превосходит 8 бит на пиксель, то в процессе визуализации необходимо будет осуществлять преобразование интенсивности из исходной глубины цвета в глубину 8 бит на пиксель.
|