Умножение матриц, серия 5: вычисления на GPU - 2

Почему переделываем тесты?

Предыдущая моя статья на эту тему была написана в феврале 2007 года, сразу после выхода первой публичной бета-версии CUDA Toolkit/CUDA SDK. Представители NVidia предупреждали, что в бета-версии производительность не является оптимальной, к релизу она будет улучшена.

За прошедшие полгода, пока я занимался совсем другими вещами, были выпущены релизы:

  • NVidia CUDA: SDK и библиотеки CUBLAS/CUFFT v1.0;
  • NVidia CUDA Display Driver 162.xx (драйвер, собственно, транслирует псевдокод в реальные программы GPU);
  • RapidMind Platform версий 2.0.0, а затем и 2.0.1.

Интересно посмотреть, стала ли производительность лучше.

Приборы и материалы: NVidia CUDA и прочие

Как и в предыдущих статьях, рассматривать будем умножение матриц, либо библиотечный вызов SGEMM. Задача очень простая в первом приближении, а во втором — вылезают разнообразные особенности. Достигнуть высокой производительности на современной аппаратуре, где память много медленнее вычислительного процессора — непросто.

Рассматривались три доступных для NVidia G80 умножителя матриц:

  1. Реализация SGEMM от RapidMind, RapidMind Platform 2.0.1.
  2. SGEMM в составе библиотеки CUBLAS, версия 1.0.
  3. Тестовый пример от NVidia, который очень подробно разобран в документации. CUDA SDK версия 1.0.
Сравнивалось все с результатами, полученными весной 2007 г. на доступных мне компьютерах общего назначения (Dual Opteron 275 и Dual Xeon 5140), CPU-расчеты делались на Goto BLAS. Повторное (после весеннего) тестирование CPU не производилось.

Все прочие параметры рассмотрены в прошлой статье, за полгода они изменились слабо, разве только NVidia GeForce 8800GTX подешевела с $600-750 до $500.

Существенные изменения

NVidia CUDA

Главное видимое изменение: практически все вызовы CUDA API, включая вызов собственно computation kernel, стали асинхронными (исключения описаны в разделе 4.5.1.5 документации), отчего старые версии тестовых программ показывают резко выросшее быстродействие. После явно добавленной синхронизации все стало на свои места.

RapidMind Platform

RapidMind Platform версий 1.9 и 2.0beta была ограничена размером матриц 1020x1020. В версии 2.0.1 этого ограничения уже нет.

Результаты тестов

Хочется напомнить, что вычисления на видеокарте проходят в три этапа:
  • Загрузка данных в видеопамять
  • Запуск вычислительного модуля, исполняемого GPU
  • Выгрузка данных в основную память компьютера
При наличии асинхронного режима (в CUDA он уже есть), загрузка-выгрузка могут осуществляться одновременно с расчетами (если области видеопамяти не пересекаются), поэтому при оценке быстродействия интересны два времени: чистое время на расчет и полное время с учетом ввода-вывода данных.

Быстродействие на перемножении матриц (MFLOP/s)
Описание тестаразмер задачи
1024 2048 4096
RapidMind 2.0.1
Только вычисления
ускорение в сравнении с 2.0beta (разы)
117 488
1.07
115 234
*
114 575
*
Вычисления + ввод-вывод
ускорение в сравнении с 2.0beta (разы)
48 859
1.46
69 536
*
82 366
*
* — RapidMind Platform 2.0b была ограничена размером задачи 1020x1020
NVidia CUBLAS 1.0
Только вычисления
ускорение в сравнении с CUDA 0.8beta (разы)
120 555
1.23
122 432
1.23
121 039
1.23
Вычисления + ввод-вывод
ускорение в сравнении с CUDA 0.8beta (разы)
61 200
1.04
85 290
1.16
100 844
1.21
NVidia CUDA: пример из SDK 1.0
Только вычисления
ускорение в сравнении с CUDA 0.8beta (разы)
48 009
1.03
48 175
1.03
47 893
1.03
Вычисления + ввод-вывод
ускорение в сравнении с CUDA 0.8beta (разы)
30 660
1.22
41 648
1.16
45 173
1.11
Вычисления на CPU
2xXeon 5140, Goto BLAS (4 потока, single precision) 26 512 45 935 47 556

Обсуждение результатов

RapidMind

Предыдущая версия RapidMind не позволяла работать с большими размерами задач, поэтому полноценного сравнения не получается. По тем двум точкам, которые у нас есть, мы видим что:
  • Вычислительная часть не стала заметно быстрее. Более того, не исключено, что рост скорости вычислений обусловлен сменой драйвера NVidia (трансляцией кода шейдеров из P-code DX9 в команды конкретного оборудование занимается драйвер).
  • Ввод-вывод данных в/из GPU стал сильно быстрее, рост производительности определяется именно скоростью I/O. Естественно, скорость I/O могла подрасти не только за счет улучшений в RapidMind, но и за счет улучшений драйвера видеокарты.

NVidia CUDA: CUBLAS

Во всех тестах, где измеряется только скорость вычислений, производительность выросла в 1.23 раза (одинаково). Другими словами, вычислительная часть CUBLAS (cuSgemm) оптимизирована, как и обещали в NVidia.

Роста скорости I/O практически нет, поэтому рост общей скорости выполнения задачи заметен только на больших размерах матриц, где вычислительная стадия является определяющей (время на вычисления зависит от куба размера матриц, а объем ввода-вывода — от квадрата).

NVidia CUDA: пример из SDK

Пример из SDK не изменился, все претензии к нему остались прежними (в двух словах: он очень далек от оптимального). Наблюдаемое ускорение вычислительной стадии в 1.03 раза связано или с лучшими оптимизациями в компиляторе, или с улучшениями в драйвере, но не с улучшениями в коде задачи (ибо улучшений нет).

Вместе с тем, ввод-вывод в CUDA SDK очевидно ускорился и очень сильно, поэтому задача малого размера, где вклад I/O в общее быстродействие наибольший, серьезно ускорилась, а с ростом размера матриц прирост скорости для задачи в-целом уменьшается..

Выводы

На сегодняшний день самые быстрые CPU от Intel способны выдать вычислительную производительность до 5GFLOP/s на один гигагерц частоты процессорного ядра для вычислений с одинарной точностью (теоретически - до 8GFLOP/s, но теоретическое быстродействие не достигается на реальных задачах). Для десктопных процессорв стоимость гигафлопса получается порядка $10-11, для серверных: $21-27 (цены московские на октябрь 2007г.). На практике, установка двух 4-ядерных процессоров в один сервер возможна, но узким местом такой системы станет пропускная способность памяти, даже при 4-х работающих ядрах этот эффект заметен.

На всякий случай, хочу отметить, что цена гигафлопса для CPU оценена для задачи, решенной наилучшим известным на сегодня способом. Если программировать примитивнее, то гигафлопсов будет меньше на порядки.

Гигафлопс на базе NVidia GeForce 8800 стоит порядка $5, если задача запрограммирована хоть сколько-нибудь оптимально. Другими словами, если нужно много считать и можно обойтись библиотеками BLAS/FFT и одинарная точность устраивает, то выбор на сегодня очевиден.

Если же хватает времени и сил на ручное программирование под GPU, то выигрыш может быть еще более значительным. Но об этом — позже.

Tags: