Традиционный путь нынешних разработчиков суперкомпьютерных систем — это кластеры (или массово-параллельные системы) серверов с процессорами, имеющими все больше процессорных ядер, что позволяет масштабировать пиковую производительность. Вместе с тем производительность собственно ядер обеспечивается не столько увеличением тактовой частоты, сколько выполнением большего числа операций с плавающей запятой за такт, например до восьми 64-разрядных чисел за такт в Power7 и микропроцессорах Intel Xeon/Sandy Bridge с AVX-расширением команд. Однако подобные прорывы происходят достаточно редко, и путь наращивания производительности за счет увеличения числа ядер большинству современных приложений не подходит. Последние, вследствие действия закона Амдала, плохо масштабируют производительность при распараллеливании на большое число ядер, поэтому в последние годы появился интерес к альтернативным аппаратным средствам повышения производительности.

Реконфигурируемые элементы

Программируемые логические матрицы позволяют строить специализированные супервычислители, свободные от недостатков кластеров, на основе процессоров x86, однако разработка приложений для них остается нетривиальной задачей.

Илья Тарасов

В качестве таких средств пробовались программируемые логические матрицы (FPGA), процессоры Cell от IBM, специальные векторные разработки ClearSpeed, но, пожалуй, единственными инструментами, которые стали активно применяться в системах высокопроизводительных вычислений (High Performance Computing, HPC), оказались графические процессоры (Graphical Processing Unit, GPU). Это определяется не только их высокими техническими характеристиками, но и возможностью для производителей устанавливать более низкие цены за счет массового выпуска. Cовременные GPU достигли высоких показателей производительности при выполнении ряда задач (особенно большой размерности), однако при их работе возникают накладные расходы по передаче через PCI-E исходных данных и результатов между хостом и процессором, что понижает эффективную производительность.

Графический вызов суперкомпьютерам

Для суперкомпьютеров написано множество прикладных пакетов, с их помощью решаются сложные вычислительные задачи, но их высокая стоимость заставляет искать им альтернативу.

Андрей Адинец, Владимир Воеводин
 

Одна из важнейших проблем применения GPU — трудности программирования. Соответствующие средства разработки обычно содержат библиотеки подпрограмм и/или API, однако при необходимости работы с нестандартными алгоритмами приходится использовать средства, не характерные для языков Си, Фортран и др., а близкие к ассемблеру. Применение графических API-интерфейсов для задач общего назначения (General Purpose, GP) привело к появлению GPGPU; в частности, разработчики nVidia предложили программистам архитектуру CUDA (Сompute Unified Device Architecture), которая стала важным подспорьем в создании HPC-приложений. Недавно появились GPU, например Fermi от nVidia [1, 2], с относительно высокой производительностью (0,5 TFLOPS) выполнения операций с плавающей запятой двойной точности, обычно требуемой в HPC-приложениях, что вместе с CUDA стимулировало рост интереса к GPU как элементам для создания высокопроизводительных платформ.

Архитектура CUDA

CUDA — «виртуальная архитектура», непосредственно отображаемая на реальное оборудование от nVidia и представляющая собой среду разработки. CUDA предполагает вызовы параллельных программ, ядер (kernel), выполняемых параллельно в виде набора параллельных нитей (такую организацию обеспечивает компилятор или программист). В архитектуре Fermi на GPU могут одновременно выполняться до 16 ядер. Нити организуются в двухуровневую структуру. Набор параллельно выполняемых нитей образует блок нитей, имеющих общую память (используемую и для коммуникаций между нитями) и синхронизируемых через барьеры. Каждая нить в блоке выполняет свой экземпляр ядра, имеет идентификатор внутри блока, свои регистры, личную локальную память, в которой располагаются, в частности, автоматические переменные, входные и выходные данные. Блоки нитей, в свою очередь, организуются в решетки (grid) блоков, представляющих собой массив блоков нитей, выполняющих одно и то же ядро, читающих данные и сохраняющих результаты в глобальной памяти GPU.

Такая двухуровневая организация нитей непосредственно отображается на архитектуру GPU, в которой имеются потоковые мультипроцессоры (Streaming Multiprocessors, SM), каждый из них выполняет блок нитей или несколько их блоков (SM выполняет блоки по 32 нити в каждом), именуемые warp («основа»). Процессорные ядра SM выполняют нити, а на GPU в целом, имеющем много SM, выполняется решетка блоков нитей (или несколько решеток). При этом нет необходимости программирования с векторными регистрами — GPU основаны на скалярных нитях и процессорах. Когда процессорные ядра одного или нескольких SM одновременно выполняют на своих исполнительных устройствах одни и те же команды, например умножения и сложения с плавающей запятой, то речь идет об операции над векторами. Поэтому GPU рассматриваются как средства векторной обработки. Количество процессорных ядер в SM, как и число самих SM, в различных архитектурах и моделях GPU различно, но для них применяется общая архитектура СUDA.

Архитектура Fermi

С появлением архитектуры Fermi стало возможным говорить о прорыве — производительность на двойной точности достигла 0,5 TFLOPS, что позволило расширить круг приложений, для которых стало целесообразным применение GPU. В Fermi имеется SM третьего поколения: 32 процессорных ядра, 16 устройств загрузки/записи в память, двойной планировщик-диспетчер нитей, конфигурируемые кэш L1 и разделяемая память. Применяется второе поколение системы команд для работы с параллельными нитями (Parallel Thread Execution, PTX), поддерживающее однородное адресное пространство, стандарт IEEE754-2008 для 32- и 64-разрядных чисел с плавающей запятой, новые команды доступа в память, предикацию для повышения производительности и другие нововведения.

 

Рис. 1. Архитектура Fermi

Архитектура Fermi (рис. 1) включает 512 процессорных CUDA-ядер, каждое из которых выполняет одну целочисленную операцию и операцию с плавающей запятой за такт. Все 512 ядер организованы в 16 SM, по 32 ядра на SM. При этом CUDA-ядра могут работать на частотах от 1,15 до 1,4 ГГц. Распределением блоков нитей по SM занимается глобальный планировщик GigaThread.

Глобальная память GPU организована в виде шести 64-разрядных разделов, что дает 384-разрядный интерфейс. В Fermi применяется память GDDR5 емкостью до 6 Гбайт. Для графических процессоров Tesla C2050/2070, ориентированных на HPC, частота передачи данных в памяти составляет 1,5 ГГц при пиковой пропускной способности 144 Гбайт/с, однако задержка составляет 400-800 тактов [2], поэтому очень важно наличие кэш-памяти.

Поддержка ECC в памяти GDDR5, учитывая более «напряженный» режим работы по сравнению с обычной DDR3 и высокую нагрузку от HPC-приложений, также представляется необходимой, однако это приводит к потерям пропускной способности (см., например, данные тестов SHOC, ft.ornl.gov/~kspafford/shoctown/shoctown.html). Кроме того, уменьшается доступная емкость памяти с 3 до 2,625 Гбайт в С2050 (с 6 до 5,25 Гбайт в С2070). Поддержку ЕСС для работы процессора в ОС Linux можно отменить средствами утилиты nvidia-smi. В Fermi поддержка кодов ECC предусмотрена и для файла регистров, и для кэшей.

Интерфейс GPU c хостом — это PCI-E x16 v2.0. В Fermi он двунаправленный, что дает пиковую суммарную пропускную способность в 12 Гбайт/с (в предыдущем поколении архитектур, G80, поддерживалась только однонаправленная передача [3]). Для повышения надежности передачи на канальном уровне применяются контрольные суммы CRC.

Каждое СUDA-ядро включает целочисленное устройство и устройство для работы с плавающей запятой (рис. 2). Каждый SM содержит 32 конвейерных исполнительных устройства для вещественных чисел с одинарной точностью и 16 устройств для работы с числами с двойной точностью, файл регистров емкостью 128 Кбайт, 16 устройств загрузки/записи в память, 4 устройства для вычисления специальных функций (они дают один результат за такт для каждой нити), кэш L1 и двойной планировщик. К специальным функциям относятся вычисление синуса, косинуса, квадратного корня и обратной величины. Целочисленные конвейерные устройства в Fermi выполняют 32-разрядные логические операции, сдвиги, сравнение и др. SM может выполнять 32 целочисленные операции и 32 операции над вещественными числами одинарной точности за такт. Как уже отмечалось, 64 Кбайт памяти конфигурируются как 48 Кбайт общей памяти плюс 16 Кбайт кэша или наоборот.

 

 

Рис. 2. Архитектура SM

 

Общий для всех SM кэш L2 имеет емкость 768 Кбайт. Ту же суммарную емкость кэшей L1 (при установке в 48 Кбайт) имеют 16 SM. Наконец, на 16 SM вместе приходится 2048 Кбайт памяти регистров. Как видно, соотношение разных уровней памяти здесь необычно, самый большой размер имеет память регистров.

Из сказанного следует, что планировщик нитей в Fermi имеет два уровня: глобальный GigaThread и двойной в каждом SM. В последнем можно запускать на выполнение одновременно до двух warp-групп нитей. Большинство команд также могут выполняться по две параллельно: две целочисленные операции, или две операции с плавающей запятой, или их смесь (или смесь с командами загрузки/записи). Время переключения контекста составляет 20-25 мкс [3], что улучшает возможности одновременного выполнения нескольких ядер приложений на одном GPU.

В PTX 2.0 три отдельных адресных пространства — личная локальная память нити, общая память блока и глобальная память для операций загрузки/записи — слиты в единое непрерывное адресное пространство. Загрузка/запись поддерживает 64-разрядную адресацию, но в настоящее время используются 40 бит, что позволяет адресовать 1 Тбайт [1].

GPU c архитектурой Fermi

Производитель предлагает три группы GPU c архитектурой Fermi: GeForce GTX 4xx для игрового сегмента, Quadro (4000/5000/6000) для профессиональной графики и Tesla 20-й серии (платы С2050/2070 и модули M2050/2070) — для HPC. Процессор GTX 480 содержит 480 ядер с частотой 1,4 ГГц, GTX 580 — 512 ядер с частотой 1,54 ГГц. Последний имеет память 1,5 Гбайт с частотой передачи данных 2 ГГц. GTX590 — это «сдвоенный» GPU (1024 ядра) и 3 Гбайт памяти, хотя сами ядра работают на более низких частотах. Пиковая пропускная способность GTX580 равна 192 Гбайт/с,GTX590 — 328 Гбайт/с.

Процессор для профессиональной графики Quadro 6000 обеспечивает производительность до 1,3 млрд треугольников в секунду, имеет память 6 Гбайт с пропускной способностью 144 Гбайт/с и поддержкой ECC. Quadro 6000 имеет 448 таких же ядер, как в Tesla.

В Tesla C2050 тоже имеется не 16, а 14 SM (448 ядер), что при частоте 1,15 ГГц дает пиковую производительность 515 GFLOPS (для одинарной точности — вдвое выше). Это обусловлено возможностью выполнения команд с плавающей запятой типа «умножить и сложить» для операндов любой точности. Применение в Tesla 448 ядер вместо возможных 512, скорее всего, связано с выходом годных и стремлением обеспечить необходимую для HPC надежность. В новейших Tesla M2090 с пиковой производительностью 665 GFLOPS представлены все 512 ядер.

Программное обеспечение

Для работы с GPU необходимо установить драйвер и средства CUDA (компилятор nvcc и ряд библиотек, среди которых библиотека программ линейной алгебры CUBLAS, а также средства поддержки языка OpenCL) и CUDA Computing SDK, содержащий ряд полезных примеров в исходных текстах для проверки работоспособности CUDA c GPU и для тестирования производительности.

Вызов базовой утилиты nvidia-smi с параметрами -a -q позволяет получить информацию обо всех установленных GPU, включая версию драйвера, серийные номера, температуру на платах, состояние вентиляторов, счетчики различных ECC-ошибок, а также нагрузку на GPU и процент использованной глобальной памяти. В состав SDK входит программа deviceQuery, которая дает общую информацию о характеристиках GPU, более близкую программисту.

Все программное обеспечение поставляется бесплатно, а ряд программных средств для HPC разработан третьими компаниями, среди этого ПО следует отметить библиотеки программ линейной алгебры CULA от EM Photonics, коммерческие средства Jacket, включающие ряд модулей для MATLAB и библиотеку программ на языке Cи. Кроме этого, имеется свободно доступная библиотека MAGMA, содержащая программы BLAS и Lapack.

Необходимо упомянуть о поддержке CUDA в среде Fortran (компиляторы PGI Accelerator Fortran и Pathscale). Например, компилятор PGI 11.4 позволяет не только вызывать CUDA-программы, подобно nvcc, но и осуществлять пересылку данных из оперативной памяти хоста в память, отведенную под переменные, обрабатываемые в GPU, и обратно. На хосте для увеличения производительности может быть установлено несколько GPU, и тогда с ними возможна параллельная работа, однако надо следить за коллизиями при одновременной работе PCI-E x16. В кластере можно установить по одному GPU на узел и применять MPI для распараллеливания [4].

Тестирование производительности

После остановки проекта Intel Larrabee и начала работы уже по новому проекту Knights Corner cопоставление процессоров архитектуры Fermi корректно проводить только с AMD Radeon HD5870 и 5890 («сдвоенный» вариант 5870). Производительность при работе с числами двойной точности в HD5870 равна 544 GFLOPS, что выше, чем у Tesla, но цена Radeon, как и GTX4xx, гораздо меньше. Однако емкость памяти в HD5870 — всего 1 Гбайт, что может быть серьезным минусом для приложений HPC. Возможно, привлекательность GPU от AMD существенно возрастет после появления Radeon HD6870, где ожидается прирост производительности примерно на треть.

Тестирование было выполнено в среде OpenSuSE Linux/x86-64 11.1 c CUDA-3.2RC2 на двухпроцессорном сервере, оснащенном процессорами Intel Xeon E5520/2.3 ГГц. Измерения производительности Tesla C2050 проведены на разных тестах: stream (двойная точность) с модифицированными кодами Massimiliano Fatica (nVidia); SHOC (Scalable HeterOgeneous Computing) v. 1.03 [5]; поставляемых с MAGMA тестах и др. Эти тесты позволяют оценить характеристики архитектуры GPU и параметры производительности процессоров для формирования рекомендаций разработчикам приложений. Кроме того, в составе набора SHOC имеются специальные тесты, проверяющие стабильность работы GPU. Система тестов SHOC ориентирована на HPC-кластеры, использующие в узлах графические процессоры. SHOC включает большое число тестов, интересных для различных приложений, но отличается неточностями документации. Среди этих тестов имеются тесты молекулярной динамики, программы для которой одними из первых стали работать на различных GPU.

По данным тестов MAGMA, реальная частота Tesla C2050 составила 1147 МГц. Пиковая производительность на SHOC — 503 (для двойной точности) и 1003 (для одинарной) GFLOPS.

Поскольку обмен данными между GPU (D) и хостом (H) может лимитировать производительность, потребовалось дополнительное исследование с помощью теста BandwidthTest из состава CUDA. Передача данных D-->H дает значение пропускной способности 3 Гбайт/с, а для H-->D — 3,6 Гбайт/с, при этом предполагается применение обычных страниц виртуальной памяти сервера, предусматривающих листание. Однако, если зафиксировать страницы в физической памяти сервера («закрепленная» память), то в этом случае достигаемая пропускная способность по тестам SHOC составит 6,1 (H-->D) и 5,8 (D-->H) Гбайт/с соответственно, что близко к теоретическому пиковому значению. Найденное примерно двойное увеличение в закрепленной памяти соответствует данным, полученным в [4]. Приведенные значения относятся к большим объемам передачи данных, а на рис. 3 дана зависимость пропускной способности от размера передаваемых данных в тестах SHOC.

При малых объемах данных время их передачи (T) определяется задержкой PCI-E (L), при больших объемах — пропускной способностью. В первом приближении можно считать T = L + pN, где N — число байтов, p — время передачи одного байта. Типичное значение L для GPU составляет 10 мкс, p — 0,4 нс/байт [4]. Величина p зависит от того, используется ли закрепленная память. В [4] получены следующие данные: L=5 мкс, p=0,5 нс/байт для D-->H с прямым отображением памяти хоста в глобальную память; задержка записи ядрами в глобальную память также равна 5 мкс. В наших тестах пропускная способность оказалась выше за счет применения новых GPU и новой версии CUDA, поэтому p получается меньше, а L при этом близка к 10 мкс.

Измерения времени передачи данных для С2050 на средствах Jacket показали, что время инициализации составляет 85 мкс, однако такую задержку можно попробовать скрыть за счет применения асинхронного обмена данными. Другим узким местом архитектуры может оказаться иерархия памяти; например, в SHOC пропускная способность для глобальной памяти составила 128 Гбайт/с по чтению, 126 Гбайт/с по записи — для последовательного обращения и 11,3/5,9 Гбайт/с соответственно для чтения/записи «с шагом». Показатели для общей памяти GPU составили 374 и 423 Гбайт/с для чтения и записи соответственно.

Стандартными тестами для памяти являются stream. В табл. 1 представлены результаты для случая, когда все данные хранятся в памяти GPU. Показатели оказались выше, чем в SHOC, и близки к пиковой пропускной способности глобальной памяти — это самые высокие из опубликованных результатов для одного GPU от nVidia. Они выше, чем данные для многопроцессорного сервера IBM Power750 Express c процессорами Power7, и даже выше, чем у векторных суперкомпьютеров NEC SX-6/7, если пересчитать их на четыре векторных процессора. Между тем именно процессоры векторных суперкомпьютеров традиционно были лидерами по рассматриваемому показателю.

 

Таблица 1. Пропускная способность памяти на тестах stream (Гбайт/с)
Система copy scale add Triad
Tesla C20501 124 124 130 130
Power750 Express2 106 106 123 123
SX-63 203 192 190 213

1 На базе Power7/3,3 ГГц, 24 ядра, DDR3/1066

2 Данные www.cs.virginia.edu/stream

3 8 векторных процессоров NEC SX-6

 

Если данные исходно хранятся в памяти хоста, то в SHOC тест triad из состава stream дает 6,5 Гбайт/с, что ниже, чем для хоста без GPU. Пониженный результат triad на GPU естествен, поскольку triad невыгодно выполнять на GPU из-за большой доли накладных расходов по обмену данными с процессором.

В табл. 2 приведены результаты тестов dgemm — MAGMA и CUBLAS — для умножения квадратных матриц. Эти данные актуальны, в частности, для ряда приложений квантовой химии, например расчета больших биомолекул и нанообъектов. Видно, что при малых размерностях CUBLAS эффективнее MAGMA. В MAGMA удалось достигнуть производительности в 301 GFLOPS, что составляет 60% пикового значения.

 

Таблица 2. Производительность GPU на dgemm (GFLOPS) для квадратных матриц n x n
Размерность матрицы MAGMA CUBLAS
32 0.6 2
64 4 12
128 26 48
256 104 113
512 235 195
1024 280 281

 

При небольших размерностях матриц n x n процессор Nehalem быстрее, чем GPU, — при n=32 даже одно процессорное ядро работает быстрее (6,6 GFLOPS), чем GPU. Понятно, что при больших n распараллеливание в хосте в принципе не может изменить большое отставание от производительности GPU, поскольку пиковая производительность одного ядра Nehalem равна всего 9 GFLOPS. Приведем для иллюстрации данные на всех восьми ядрах: 43 GFLOPS для n=2000, 67 GFLOPS для n=9000.

В SHOC проводится прямое сопоставление dgemm-производительности при расчетах только на GPU и с учетом времени передачи матриц в GPU и обратно. Для четырех классов размерности задач (-s=1,2,3,4) достигнутые значения составили 71/29; 209/123; 285/194 и 297/240 GFLOPS соответственно («чистые» GPU-расчеты/время передач).

***

Круг HPC-приложений, использующих СUDA, уже достаточно широк: молекулярное моделирование, квантово-химические программы Firefly, ориентированные на большие молекулы, задачи поиска нефтяных месторождений, анализ котировок опционов. Приведенные данные позволяют сделать вывод о том, что в области HPC графические процессоры постепенно становятся дополнением универсальных. Наибольший интерес среди них, очевидно, вызывают GPU c архитектурой Fermi, которые, однако из-за накладных расходов на обмен данными с GPU можно эффективно применять не для всех задач.

Литература

  1. Nvidia's Next Generation CUDA Compute Architecture: Fermi, Whitepaper, V1.1. Nvidia, 2009.
  2. M. Fried, GPGPU Architecture Comparison of Nvidia and ATI GPUs. Microway, April, 2010.
  3. D. Patterson, The Top 10 Innovations in the New Nvidia Fermi Architecture, and the Top 3 Next Challenges. Parallel Computing Research Laboratory, U.C. Berkeley, Sept. 30, 2009.
  4. O. S. Lawlor, Message Passing for GPGPU Clusters: cudaMPI. IEEE Cluster PPAC Workshop, 2009.
  5. A. Danalis, G. Marin, C. McCurdy, J. Meredith, P. Roth, K. Spafford, V. Tipparaju, J. Vetter, The Scalable HeterOgeneous Computing (SHOC) Benchmark Suite, Proc. 3rd Workshop on General-Purpose Computation on Graphics Processors, March 2010

Михаил Кузьминский (kus@free.net) – старший научный сотрудник учреждения РАН «Институт органической химии им. Н. Д. Зелинского» (Москва).