Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Центр микро- и наномасштабной динамики дисперсных систем Модель программирования CUDA Марьин Д. Ф. Уфа, 2011г. 1 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Архитектура Tesla 10 Архитектура Tesla 20 Вычислительная конфигурация Общая архитектура GPU Tesla 10 series SPA (Streaming Processor Array) — набор TPC. 2 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Архитектура Tesla 10 Архитектура Tesla 20 Вычислительная конфигурация Архитектура TPC (Texture Processing Cluster) Tesla 10 TEX — Texture block SM — Streaming Multiprocessor SP — Scalar Processor (CUDA–ядро) SFU — Super Function Unit 3 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Архитектура Tesla 10 Архитектура Tesla 20 Вычислительная конфигурация Архитектура Tesla 20 Объединенный L2 кэш (768 Kb) До 1 Tb памяти (64-битная адресация) Общее адресное пространство памяти Одновременное исполнение ядер, копирования памяти (CPU→GPU, GPU→CPU) Одновременное исполнение ядер (до 16) 4 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Архитектура Tesla 10 Архитектура Tesla 20 Вычислительная конфигурация Архитектура SM Tesla 20 32 ядра на SM Одновременное исполнение 2х варпов 48 Kb разделяемой памяти + 16 Kb кэш; или 16 Kb разделяемой + 48 Kb кэш 5 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Архитектура Tesla 10 Архитектура Tesla 20 Вычислительная конфигурация Каждый поток и блок потоков имеют идентификаторы. blockIdx — индекс block’а внутри grid ’а (1D, 2D). threadIdx — индекс thread ’а внутри block’а (1D, 2D, 3D). 6 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Модель программирования CUDA. CPU Основной процесс приложения CUDA работает на CPU (host): 7 1 инициализирует GPU 2 распределяет память на видеокарте и системе 3 копирует данные в память видеокарты 4 запускает несколько копий процессов kernel на видеокарте 5 копирует полученные результаты из видеопамяти 6 освобождает память 7 завершает работу Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Модель программирования CUDA. GPU GPU выполняет следующую работу: 8 1 задача разбивается на подзадачи 2 входные данные делятся на блоки, которые вмещаются в разделяемую память 3 каждый блок обрабатывается блоком потоков 4 над данными в разделяемой памяти проводятся соответствующие вычисления 5 результаты копируются из разделяемой памяти обратно в глобальную Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Расширения языка CUDA С — это расширение языка C/C++ спецификаторы для функций и переменных новые встроенные типы встроенные переменные (внутри ядра) директива для запуска ядра из C кода 9 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Спецификаторы функций Определяют, где может выполняться функция и откуда она может быть запущена: Спецификатор __host__ __global__ __device__ Выполняется на host device device Может вызываться из host host device __host__ опционален; __host__ и __device__ могут быть использованы вместе. Пример: __global__ v o i d Func ( f l o a t * arg1 , i n t arg2 , 10 ...); Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Ограничения на спецификаторы функций Ограничения на функции выполняемые на GPU (__device__ и __global__): не поддерживается рекурсия; не поддерживается переменное число входных аргументов; не поддерживаются static-переменные внутри функции; __device__ функция не поддерживает взятие адреса; __global__ обозначает kernel и соответствующая функция должна возвращать значение типа void; __device__ функция является встроенной. Можно использовать __noinline__ — тело функции должно быть в том же файле; — компилятор не среагирует, если функция с параметрами–указателями, или большое число аргументов. 11 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Директива вызова ядра Func <<< g r i d , b l o c k [ , b y t e s [ , s t r e a m i d ] ] >>> ( [ arg1 , . . . ] ) ; grid — переменная/значение типа dim3, задаёт размер grid’a (в блоках); block — переменная/значение типа dim3, задаёт размер блока (в нитях); bytes — переменная/значение типа size_t, задаёт дополнительный объём shared-памяти, которая должна быть динамически выделена; streamid — переменная/значение типа cudaStream_t, задаёт поток (CUDA stream), в котором должен произойти вызов, по умолчанию — 0. 12 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Пример __global__ v o i d k e r n e l ( v o i d ) { } i n t main ( v o i d ) { k e r n e l <<< 1 6 , 3 2 >>> ( ) ; return 0; } 13 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Добавлены 1,2,3,4-мерные вектора из базовых типов: (u)char1, (u)char2, (u)char3, (u)char4, (u)short1, (u)short2, (u)short3, (u)short4, (u)int1, (u)int2, (u)int3, (u)int4, (u)long1, (u)long2, (u)long3, (u)long4, float1, float2, float3, float4, longlong1, longlong2, double1, double2. Не поддерживаются векторные покомпонентные операции — это необходимо явно делать для каждой компоненты. 14 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Для создания значений-векторов заданного типа typeName служит конструкция вида make_<typeName>. Обращение к компонентам вектора производится по именам — x, y, z и w. int2 int2 a = make_int2 b = make_int2 ( 1, 7 ); ( 2, 0 ); // a = a + b a . x += b . x ; a . y += b . y ; f l o a t 4 c = mak e_float4 ( 1 , 2 , 3 . 4 f , 0 . 1 f ) ; c.y = a.x + c.x; a . x = a . y + ( int ) c . z ; c . x += c . y + c . z + c . w ; 15 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных dim3 — uint3 тип для задания размерности. Обладает конструктором, инициализирующим все не заданные компоненты единицами: dim3 varname ( [ x [ , y [ , z ] ] ] ) ; Пример: dim3 b l o c k s ( 1 6 , 16 ) ; // b l o c k s ( 1 6 , 1 6 , 1 ) dim3 g r i d ( 256 ) ; // g r i d ( 2 5 6 , 1 , 1 ) i n t blockDimX = b l o c k s . x ; 16 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Добавлены следующие специальные переменные: gridDim — размер grid’а (имеет тип dim3) blockDim — размер блока (имеет тип dim3) blockIdx — индекс текущего блока в grid’е (имеет тип uint3) threadIdx — индекс текущей нити в блоке (имеет тип uint3) warpSize — размер warp’а (имеет тип int) Ограничения: нельзя брать адрес встроенных переменных нельзя присвоить значение встроенной переменной 17 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных CPU C code: float * a; ... f o r ( i n t i = 0 ; i < N; i++ ) { a [ i ] = a [ i ] + 1.5 f ; } CUDA C code: __global__ v o i d k e r n e l ( f l o a t * a , i n t N ) { // g l o b a l t h r e a d i n d e x i n t i = b l o c k I d x . x * blockDim . x + t h r e a d I d x . x ; if ( i < N ) a [ i ] = a [ i ] + 1.5 f ; } 18 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Спецификаторы переменных Указывают на область видео–памяти, где они будут храниться. __device__ __constant__ __shared__ Пример: __device__ i n t a [ 1 0 0 ] ; 19 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных __device__ Описывает переменную, которая будет находиться на устройстве. Может быть уточнен другими спецификаторами. Переменная: если не указано особо, то находится в глобальной памяти имеет время жизни всего приложения доступна всем потокам и хосту через runtime library 20 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных __constant__ опционально используется с __device__ Переменная: находится в константной памяти имеет время жизни всего приложения доступна всем потокам и хосту через runtime library 21 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных __shared__ опционально используется с __device__ Переменная: находится в разделяемой памяти блока потоков имеет время жизни блока доступна только потокам этого блока 22 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных short array0 [ 1 2 8 ] ; f l o a t array1 [ 6 4 ] ; int array2 [ 2 5 6 ] ; e x t e r n __shared__ c h a r a r r a y [ ] ; __device__ v o i d Func ( ) { sh or t * array0 = ( sh or t *) array ; f l o a t * array1 = ( f l o a t *) & array0 [ 1 2 8 ] ; int * array2 = ( i n t *) & array1 [ 6 4 ] ; } 23 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Спецификаторы функций Директива вызова ядра Добавленные типы переменных Добавленные переменные Спецификаторы переменных Ограничения на спецификаторы переменных не могут быть применены к полям структуры (struct или union) не могут быть применены к формальным и локальным переменным функций, исполняемых на хосте __device__ и __constant__ переменные могут использоваться только в пределах одного файла, их нельзя объявлять как extern запись в переменные типа __constant__ может осуществляться только CPU при помощи специальных функций __shared__ переменные не могут быть инициализированы при объявлении 24 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Добавленные функции Асинхронные функции Возвращаемые значения функций CUDA поддерживает все математические функции из стандартной библиотеки C. (sin) Лучше использовать float–аналоги стандартных функций. (sinf) CUDA предоставляет специальный набор функций пониженной точности. (__sinf) Для ряда функций можно задать способ округления при помощи суффикса: rn — округление к ближайшему rz — округление к нулю ru — округление вверх rd — округление вниз f l o a t x = 1 . 7 2 ; __sinf_rz ( x ) ; Есть ряд оптимизированных функций для работы с целыми числами. 25 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Добавленные функции Асинхронные функции Возвращаемые значения функций #d e f i n e N ( 1 0 2 4 * 1 0 2 4 ) __global__ v o i d k e r n e l ( f l o a t * data ) { i n t i d x = b l o c k I d x . x * blockDim . x + t h r e a d I d x . x ; f l o a t x = 2 . 0 f * 3 . 1 4 1 5 9 2 6 f * ( f l o a t ) i d x / ( f l o a t ) N; data [ i d x ] = s i n f ( __fsqrt_rz ( x ) ) ; } i n t main ( i n t argc , c h a r * argv [ ] ) { f l o a t a [N ] ; f l o a t * dev = NULL; dim3 t h r e a d s P e r B l o c k = dim3 ( 1 2 8 , 1 ) ; dim3 b l o c k s P e r G r i d ( N / t h r e a d s P e r B l o c k . x , 1 ) ; cudaMalloc ( ( v o i d * * ) & dev , N * s i z e o f ( f l o a t ) ) ; k e r n e l <<< t h r e a d s P e r B l o c k , b l o c k s P e r G r i d >>> ( dev ) ; cudaMemcpy ( a , dev , N * s i z e o f ( f l o a t ) , cudaMemcpyDeviceToHost ) ; cudaFree ( dev ) ; return 0; } 26 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Добавленные функции Асинхронные функции Возвращаемые значения функций f l o a t a [N ] ; f l o a t * dev = NULL; // a l l o c a t e memory on t h e GPU by N e l e m e n t s cudaMalloc ( ( v o i d * * ) & dev , N * s i z e o f ( f l o a t ) ) ; // run N t h r e a d s i n b l o c k s o f 128 t h r e a d s // p e r f o r m e d on t h e t h r e a d f u n c t i o n - k e r n e l // data a r r a y - dev dim3 t h r e a d s P e r B l o c k = dim3 ( 1 2 8 , 1 ) ; dim3 b l o c k s P e r G r i d ( N / t h r e a d s P e r B l o c k . x , 1 ) ; k e r n e l <<< t h r e a d s P e r B l o c k , b l o c k s P e r G r i d >>> ( dev ) ; // copy data from GPU memory (DRAM) t o CPU memory cudaMemcpy ( a , dev , N * s i z e o f ( f l o a t ) , cudaMemcpyDeviceToHost ) ; cudaFree ( dev ) ; // r e l e a s e GPU memory 27 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Добавленные функции Асинхронные функции Возвращаемые значения функций #d e f i n e N ( 1 0 2 4 * 1 0 2 4 ) __global__ v o i d k e r n e l ( f l o a t * data ) { // number ( i d ) o f t h e c u r r e n t t h r e a d i n t i d x = b l o c k I d x . x * blockDim . x + t h r e a d I d x . x ; f l o a t x = 2 . 0 f * 3 . 1 4 1 5 9 2 6 f * ( f l o a t ) i d x / ( f l o a t ) N; // f i n d t h e v a l u e and w r i t e i t i n t o a r r a y data [ i d x ] = s i n f ( __fsqrt_rz ( x ) ) ; // } Для каждого элемента массива запускается отдельная нить, вычисляющая требуемое значение. Каждая нить обладает уникальным id. 28 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Добавленные функции Асинхронные функции Возвращаемые значения функций Асинхронные функции Асинхронность — управление возвращается до реального завершения требуемой операции. запуск ядра функции копирования памяти, имена которых оканчиваются на Async функции копирования памяти device ↔ device функции инициализации памяти 29 Повторение Модель программирования CUDA. Расширения языка Расширения языка. Функции Добавленные функции Асинхронные функции Возвращаемые значения функций Возвращаемые значения функций Каждая функция CUDA runtime API (кроме запуска ядра) возвращает значение типа cudaError_t. При успешном выполнении возвращается cudaSuccess, иначе — код ошибки. Получить описание ошибки в виде строки по ее коду можно с помощью функции: char * 30 c u d a G e t E r r o r S t r i n g ( cudaError_t code ) ;