Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Центр микро- и наномасштабной динамики дисперсных систем Модель памяти GPU/CUDA Global memory Марьин Д. Ф. Уфа, 2011г. 1 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory На GPU/CUDA выделяют 6 видов памяти: 2 1 регистровая 2 разделяемая 3 локальная 4 глобальная 5 константная 6 текстурная Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Глобальная, локальная, текстурная и память констант — локальная видеопамять GPU. Отличие в различных алгоритмах кэширования и моделях доступа. CPU может обновлять и запрашивать только внешнюю память: глобальную, константную и текстурную. 3 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Registers — СОЗУ в мультипроцессоре (32 -разрядная). Register file — все регистры мультипроцессора. Расположение: multiprocessor Кэшируемость: no Уровень выделения: on chip Доступ: GPU — R/W, CPU — no Скорость работы: «максимальная» Уровень доступа: per-thread, SP Время жизни: thread 4 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Распределение регистров На один мультипроцессор доступно 1024 ÷ 16384 регистра. Регистры распределяются на этапе компиляции. Пример: Регистров на мультипроцессор — 16384 Размер блока (число потоков) — 256 Число регистров на один поток: 16384/256 = 64 Примечание: для большей эффективности надо стараться занимать меньше 64 или даже 32 регистров, чтобы на одном мультипроцессоре могло исполняться несколько блоков! 5 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Constant memory — физически не отделена от глобальной памяти. Константная память выделяется при помощи спецификатора __constant__. Расположение: DRAM Кэшируемость: yes, 8 KB at MP Уровень выделения: on chip L1 cache Доступ: GPU — R/O, CPU — R/W Скорость работы: высокая (cache) / низкая (400–600 тактов) Уровень доступа: per-grid, CPU Время жизни: выделяется CPU Кэш существует в единственном экземпляре для одного мультипроцессора, а значит, общий для всех задач внутри блока. 6 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Функции runtime library работы с памятью cudaMemcpyToSymbol ( . . . ) ; cudaMemcpyFromSymbol ( . . . ) ; cudaMemcpyToSymbolAsync ( . . . ) ; cudaMemcpyFromSymbolAsync ( . . . ) ; cudaGetSymbolAddress ( . . . ) ; cudaGetSy mbolSize ( . . . ) ; 7 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory template <c l a s s T> cudaError_t cudaMemcpyToSymbol ( c o n s t T& symbol , c o n s t v o i d * s r c , s i z e _ t count , size_t o f f s e t = 0 , enum cudaMemcpyKind k ind = cudaMemcpyHostToDevice ) ; count — размер в байтах; offset — сдвиг в байтах от начала symbol; kind — cudaMemcpyHostToDevice, cudaMemcpyDeviceToDevice. template <c l a s s T> cudaError_t cudaMemcpyToSymbolAsync ( . . . , cudaStream_t stream ) ; stream — дескриптор потока, позволяет организовать несколько потоков команд. 8 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Пример работы с константной памятью На стороне хоста (в .cu файле): f l o a t hostData [ 2 5 6 ] ; // h o s t memory __constant__ f l o a t constData [ 2 5 6 ] ; // c o n s t a n t memory // h o s t memory data -> d e v i c e c o n s t a n t memory data cudaMemcpyToSymbol ( constData , hostData , s i z e o f ( hostData ) , 0 , cudaMemcpyHostToDevice ) ; На стороне устройства: __global__ v o i d k e r n e l ( f l o a t * pos ) { i n t i n d e x = b l o c k I d x . x * blockDim . x + t h r e a d I d x . x ; pos [ i n d e x ] = pos [ i n d e x ] * constData [ i n d e x ] ; } 9 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Локальная память — небольшой объём DRAM, используемый компилятором в случаях, когда локальные данные процедур занимают слишком большой размер, или когда компилятор не может вычислить для них некоторый постоянный шаг при обращении. Расположение: DRAM Кэшируемость: no Уровень выделения: DRAM Доступ: GPU — R/W, CPU — no Скорость работы: низкая (латентность — 400–600 тактов) Уровень доступа: per-thread, SP Время жизни: thread Примечание: нет механизмов, позволяющих явно запретить компилятору использование локальной памяти для конкретных переменных. 10 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Global memory — DRAM GPU. Обладает высокой пропускной способностью (более 100 ГБ/с) и возможностью произвольной адресации глобальной памяти. Глобальная память выделяется при помощи спецификатора __device__ или особым образом. Расположение: DRAM Кэшируемость: no Уровень выделения: DRAM Доступ: GPU — R/W, CPU — R/W Скорость работы: низкая (латентность — 400–600 тактов) Уровень доступа: per-grid, CPU Время жизни: выделяется CPU Назначение: передача данных между CPU и GPU. 11 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Функции управления памятью Выделение памяти на устройстве: cudaError_t cudaMalloc ( v o i d ** devPtr , s i z e _ t count ) ; count — размер в байтах. Освобождение памяти на устройстве: cudaError_t cudaFree ( v o i d * dev Ptr ) ; 12 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Для эффективного доступа к глобальной памяти важным требованием является выравнивание данных в памяти. cudaError_t c u d a M a l l o c P i t c h ( v o i d ** devPtr , s i z e _ t * p i t c h , s i z e _ t widthInBy tes , s i z e _ t h e i g h t ) ; при выделении памяти может увеличить объём памяти под каждую строку, чтобы гарантировать выравнивание всех строк. pitch — шаг распределения памяти в байтах. Если при помощи cudaMallocPitch выделялась память под матрицу из элементов типа T, то для получения адреса элемента, расположенного в строке row и столбце col, используется следующая формула: T * item = ( T * ) ( ( char * ) baseAddress + row * pitch) + col; 13 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Пример использования cudaMallocPitch для выделения двухмерного массива размерами width x height // h o s t s i d e code f l o a t * dev Ptr ; size_t pitch ; int height = 10; i n t width = 6 3 ; c u d a M a l l o c P i t c h ( ( v o i d ** ) & devPtr , & p i t c h , width * s i z e o f ( f l o a t ) , h e i g h t ) ; myKernel <<< 1 0 , 64 >>> ( devPtr , p i t c h , width , h e i g h t ) ; widthInBytes = 252 pitch = 256 14 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory // d e v i c e s i d e code __global__ v o i d myKernel ( f l o a t * devPtr , i n t p i t c h , i n t width , i n t h e i g h t ) { f o r ( i n t row = 0 ; row < h e i g h t ; ++row ) { f l o a t * rowPtr= ( f l o a t * ) ( ( c h a r * ) dev Ptr + row * p i t c h ) ; f o r ( i n t c o l = 0 ; c o l < width ; ++c o l ) { f l o a t e l e m e n t = rowPtr [ c o l ] ; ... rowPtr [ c o l ] = row * width + c o l ; } } } T * item = ( T * ) ( ( char * ) baseAddress + row * pitch) + col; 15 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory cudaError_t cudaMallocHost ( v o i d ** h o s t P t r , s i z e _ t s i z e ) ; page–locked (pinned) память со стороны хоста, которая доступна напрямую устройству. Повышает скорость передачи данных между CPU и GPU для функций cudaMemcpy*(). Виртуальная память обладает большей пропускной способностью, чем страничная память (malloc()). Примечание: Является ограниченным ресурсом и чрезмерное её использование может отрицательно сказаться на быстродействии всей системы. Лучше использовать как буффер для обмена данными между хостом и устройством. cudaError_t cudaFreeHost ( v o i d * h o s t P t r ) ; 16 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Пересылка данных: cudaError_t cudaMemset ( v o i d * devPtr , i n t v a l u e , s i z e _ t count ) ; count — размер в байтах; value — значение. Копирование данных: cudaError_t cudaMemcpy( v o i d * dst , c o n s t v o i d * s r c , s i z e _ t count , enum cudaMemcpyKind k ind ) ; cudaError_t cudaMemcpyAsync ( . . . cudaStream_t stream ) ; ... 17 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Register Constant memory Local memory Global memory Пример пересылки данных: int n = 512; int numBytes = n * s i z e o f ( f l o a t ) ; f l o a t * a = NULL; f l o a t * aDev = NULL; a = ( f l o a t * ) m a l l o c ( n* s i z e o f ( f l o a t ) ) ; cudaError_t e r r o r = cudaMalloc ( ( v o i d **)&aDev , numBytes ) ; dim3 t h r e a d s = dim3 ( 1 2 8 ) ; dim3 b l o c k s = dim3 ( n / t h r e a d s . x ) ; cudaMemset ( aDev , 0 , n ) ; v e c t o r s S u m K e rn el <<< b l o c k s , t h r e a d s >>> ( aDev ) ; cudaMemcpy ( a , aDev , numBytes , cudaMemcpyDeviceToHost ) ; cudaFree ( aDev ) ; 18 free (a ); Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Обращение к глобальной памяти происходит через чтение/запись 32/64/128-битовых слов. Важно, что адрес, по которому происходит доступ, должен быть выровнен по размеру слова (кратен размеру слова в байтах). Пример выровненного и невыровненного 4-х байтного слова. 19 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Все функции выделяющие глобальную память выделяют её выровненной по 256 байтам. Пусть есть массив из следующих структур в глобальной памяти: s t r u c t v ec3 { float a; float b; float c ; } Каждый элемент массива — 12 байт. Адрес первого элемента выровнен по 16 байтам, но адрес второго элемента — нет, и его чтение потребует двух обращений. 20 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Выравнивание: s t r u c t __align__ ( 1 6 ) v ec3 { float a; float b; float c ; } Теперь все элементы массива будут хранится по адресам кратным 16 байтам. 21 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Объединение запросов в глобальную память (coalescing) GPU имеет возможность объединять несколько запросов к глобальной памяти в один (coalescing). Все обращения MP к памяти происходят независимо для каждой половины warp’a. Максимальное объединение — все запросы одного полу-warp’a удается объединить в один большой запрос на чтение из глобальной памяти. 22 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Условия возможности объединения все нити обращаются к 32(CP от 1.2)/32/64-битовым словам, давая в результате один 32(CP от 1.2)/64/128-байтный блок; получивщийся блок выровнен по своему размеру (адрес кратен 32(CP от 1.2)/64/128); все 16 слов, к которым обращаются нити лежат в пределах одного блока; нити обращаются к словам последовательно: k–ая нить обращается к k–му слову; допускается, что отдельные нити пропустят обращение к соответствующим словам. Если нити полу-warp’a не удовлетворяют любому условию, то каждое обращение к памяти происходит как отдельная транзакция! 23 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Гораздо эффективнее, с точки зрения объединения запросов к памяти, использование не массивов структур, а структуры массивов. s t r u c t __align__ ( 1 6 ) A { float a; float b; int c ; } A array [ 2 5 6 ] ; ... f l o a t ga = a r r a y [ t h r e a d I d x . x ] . a ; A gs = array [ threadIdx . x ] ; Не приведет к объединению запросов! Понадобится 16 транзакций на полу-warp. 24 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью float float int c ... float float float Выравнивание Coalescing Структуры массивов a [256]; b [256]; [256]; ga = a [ t h r e a d I d x . x ] ; gb = b [ t h r e a d I d x . x ] ; gc = c [ t h r e a d I d x . x ] ; Приведет к объединению запросов всех запросов нитей полу-warp’a! Понадобится 3 транзакции на полу-warp. 25 Модель памяти GPU/CUDA Оптимизация работы с глобальной памятью Выравнивание Coalescing Структуры массивов Основные способы: выравнивание объединение запросов в глобальную память (coalescing) использование не массивов структуры, а структур массивов 26