
847477b140bd6bbe87d3c5df8a1f0bd0.ppt
- Количество слайдов: 21
Автоматизация разработки приложений для графических ускорителей с использованием переписывающих правил Анатолий Дорошенко, Константин Жереб Институт программных систем НАН Украины Киевское отделение МФТИ
Почему графические ускорители • Специализированные устройства, доступные на большинстве компьютеров • Изначально разработаны для решения графических задач • Рыночные требования привели к значительному повышению производительности • Можно использовать для общецелевых вычислений (General Purpose computation on Graphical Processing Units, GPGPU)
Производительность и стоимость
Архитектура GPU • 16 мультипроцессоров • 128 ядер • 8192 регистра • 16 KБ разделяемой памяти
Программирование GPU • Использование графических средств (шейдеры) • Специализированные средства GPGPU – NVidia CUDA – AMD Stream – Open. CL
Модель программирования CUDA • Вычислительные ядра (kernel) • Каждое ядро выполняется на многих потоках (thread) • Потоки объединены в блоки (block), которые объединены в решетки (grid)
Взаимодействие с CPU • Язык С – два способа вызова – C for CUDA – расширение языка С – Driver API – набор функций (сложнее, но предоставляет больший контроль) • C#, Java – Библиотеки от сторонних разработчиков (CUDA. NET, j. CUDA) – Основаны на driver API (сложность вызова) – Ядра нужно все равно писать на C for CUDA
Почему автоматизация • Сложная модель программирования • Сложная иерархия памяти • Эффективные программы требуют низкоуровневой оптимизации • Сложное взаимодействие с языками высокого уровня
Переписывающие правила • Программа представляется в виде термов t=f(t 1, . . . , tn) • Использование переписывающих правил source [condition] destination [action] – source – исходный терм (образец) – condition – условие применения (необязательно) – destination – преобразованный терм – action – дополнительное действие (необязательно)
Платформа Termware • Платформа переписывающих правил • Декларативное описание • Варианты использования – Самостоятельно (командная строка, графический интерфейс) – Интегрируется в приложения • Изначально на Java, портирована на C#
Почему переписывающие правила • Способ описания преобразований программ • Декларативное описание • В сложных случаях можно использовать процедурный код
Что автоматизируем • Переход к использованию CUDA – Входные данные – программа на C# • Оптимизация для CUDA – Структура циклов – Доступ к памяти • Пример – игра «Жизнь»
Переход от C# к С for CUDA Скомпилированное ядро C for CUDA Ядро CUDA Интенсивные вычисления C# CUDA. NET Исходная программа Вызов ядра C# Преобразованная программа . cubin
Пример правил Генерация ядра CUDA • _Cuda. Kernel 2 D($name, $params, $body, $idx 1, $idx 2) -> _Cuda. Function. Kernel($name, $params, [_Prepare. Idx($idx 1, x), _Prepare. Idx($idx 2, y), _Cs. To. Cuda($body)]) • _Cuda. Function. Kernel($name, $params, $body) -> Function([Extern. C, __global__], void, $name, $params, $body) • _Prepare. Idx($idx, $coor) -> Declaration. Assignment( $idx, int, _Cuda. Idx($coor)) • _Cuda. Idx($coor) -> Dot(block. Idx, $coor) * Dot(block. Dim, $coor) + Dot(thread. Idx, $coor)
Вызов ядра • • Проверка наличия CUDA Инициализация ядра Копирование входных данных в графическую память Передача параметров ядра Вызов ядра Копирование результатов Освобождение графической памяти
Сгенерированный код // Init CUDA, select 1 st device. //pass parameters CUDA cuda = new CUDA(0, true); // load kernel cuda. Set. Parameter(func, 0, (uint)dev_input. Pointer); string path = Path. Combine(Environment. Current. Directory, "life_kernel. cubin"); cuda. Set. Parameter(func, Int. Ptr. Size, (uint)dev_output. Pointer); cuda. Load. Module(path); cuda. Set. Parameter. Size(func, (uint)(2*Int. Ptr. Size)); CUfunction func = cuda. Get. Module. Function("life_kernel"); //call kernel //. . . // allocate memory and copy to device CUdeviceptr dev_input = cuda. Copy. Host. To. Device<int>(input); cuda. Set. Function. Block. Shape(func, BLOCK_SIZE, 1); cuda. Launch(func, FIELD_SIZE / BLOCK_SIZE, FIELD_SIZE / BLOCK_SIZE); //. . . CUdeviceptr dev_output = cuda. Copy. Host. To. Device<int>(output); //copy from device and release memory //. . . cuda. Free(dev_input); cuda. Copy. Device. To. Host<int>(dev_output, output); cuda. Free(dev_output);
Оптимизация Больше вычислений на поток 0 1 2 … 15 0 0 0 … 0 16 17 18 … 31 1 … 1 32 33 34 … 47 2 2 2 … … … … 255 240 241 242 255 255
Оптимизация Разделяемая (shared) память • Добавляем буферы (свой для каждого блока) • Каждый поток копирует свою часть данных в буфер • Все вычисления – в буферах, без доступа в глобальную память • Результаты копируются в глобальную память
Повышение производительности Вариант CPU GPU, без оптимизаций GPU, оптимизация Время, с 15, 66 1, 89 0, 614 Ускорение 1 8, 3 25, 5 • Поле 512 x 512, 1000 итераций • Без оптимизаций ускорение в 8 раз • Практически не требовало вмешательства разработчика • Оптимизации позволили достичь 25 -кратного ускорения
Выводы • GPU – новая перспективная платформа • Программирование для GPU сейчас сложно и требует автоматизации • Автоматизация преобразований – переписывающие правила • Распараллеливание и оптимизация программ для GPU – Достигнуто ускорение в 25 раз • Дальнейшие исследования – Новые преобразования – Новые задачи – Поддержка других технологий
Спасибо за внимание! Вопросы? doroshenko@intspei. com zhereb@gmail. com
847477b140bd6bbe87d3c5df8a1f0bd0.ppt