Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 11 лет назад пользователемАнгелина Недовесова
1 Лекторы: Боресков А.В. (ВМиК МГУ) Харламов А.А. (NVidia) CUDA Stream. Иерархия памяти в CUDA. Глобальная память.
2 2011 План Типы памяти Основы CUDA C API – Выделение глобальной памяти Pitch linear Pinned Coalescing – Примеры CUDA Streams – Примеры Thrust – Примеры
3 2011 Tesla 20Tesla 10
4 2011 Как скомпилировать CUDA код NVCC – компилятор для CUDA – Основными опциями команды nvcc являются: – -deviceemu - компиляция в режиме эмуляции, весь код будет выполняться в многонитевом режиме на CPU и можно использовать обычный отладчик (хотя не все ошибки могут проявится в таком режиме) – --use_fast_math - заменить все вызовы стандартных математических функций на их быстрые (но менее точные) аналоги – -o - задать имя выходного файла CUDA файлы обычно носят расширение.cu
5 2011 Основы CUDA host API Два API Низкоуровневый driver API (cu*) Высокоуровневый runtime API (cuda*) – Реализован через driver API Не требуют явной инициализации Все функции возвращают значение типа cudaError_t – cudaSuccess в случае успеха
6 2011 Основы CUDA API Многие функции API асинхронны: Запуск ядра Копирование при помощи функций *Async Копирование device device Инициализация памяти
7 2011 Основы CUDA API char * cudaGetErrorString ( cudaError_t ); cudaError_t cudaGetLastError (); cudaError_t cudaThreadSynchronize (); cudaError_t cudaEventCreate ( cudaEvent_t * ); cudaError_t cudaEventRecord ( cudaEvent_t * ); cudaStream_t ); cudaError_t cudaEventQuery ( cudaEvent_t ); cudaError_t cudaEventSynchronize ( cudaEvent_t ); cudaError_t cudeEventElapsedTime ( float * time, cudaEvent_t start, cudaEvent_t stop ); cudaError_t cudaEventDestroy ( cudaEvent_t ); cudaError_t cudaGetDeviceCount ( int * ); cudaError_t cudaGetDevicePropertis ( cudaDeviceProp * props, int deviceNo );
8 2011 CUDA Compute Capability Возможности GPU обозначаются при помощи Compute Capability, например 1.1 Старшая цифра соответствует архитектуре Младшая – небольшим архитектурным изменениям Можно получить из полей major и minor структуры cudaDeviceProp
9 2011 Получение информации о GPU int main ( int argc, char * argv [] ) { intdeviceCount; cudaDevicePropdevProp; cudaGetDeviceCount ( &deviceCount ); printf ( "Found %d devices\n", deviceCount ); for ( int device = 0; device < deviceCount; device++ ) { cudaGetDeviceProperties ( &devProp, device ); printf ( "Device %d\n", device ); printf ( "Compute capability : %d.%d\n", devProp.major, devProp.minor ); printf ( "Name : %s\n", devProp.name ); printf ( "Total Global Memory : %d\n", devProp.totalGlobalMem ); printf ( "Shared memory per block: %d\n", devProp.sharedMemPerBlock ); printf ( "Registers per block : %d\n", devProp.regsPerBlock ); printf ( "Warp size : %d\n", devProp.warpSize ); printf ( "Max threads per block : %d\n", devProp.maxThreadsPerBlock ); printf ( "Total constant memory : %d\n", devProp.totalConstMem ); } return 0; }
10 Compute Capability GPUCompute Capability Tesla S GeForce GTX GeForce 9800 GX2 1.1 GeForce 9800 GTX 1.1 GeForce 8800 GT 1.1 GeForce 8800 GTX 1.0 RTM Appendix A.1 CUDA Programming Guide
11 2011 Compute Capability Compute Caps. – доступная версия CUDA – Разные возможности HW – Пример: В 1.1 добавлены атомарные операции в global memory В 1.2 добавлены атомарные операции в shared memory В 1.3 добавлены вычисления в double Узнать доступный Compute Caps. можно через cudaGetDeviceProperties() – См. CUDAHelloWorld Сегодня Compute Caps: – Влияет на правила работы с глобальной памятью
12 2011 Компиляция программ Используем утилиту make/nmake, явно вызывающую nvcc Используем MS Visual Studio – Подключаем cuda.rules – Используем CUDA Wizard ( wizard)
13 Типы памяти в CUDA Тип памяти ДоступУровень выделения Скорость работы Регистры R/WPer-threadВысокая(on-chip) Локальная R/WPer- thread Низкая (DRAM) Shared R/WPer-blockВысокая(on-chip) Глобальна я R/WPer-gridНизкая (DRAM) Constant R/OPer-gridВысокая(L1 cache) Texture R/OPer-gridВысокая(L1 cache)
14 2011 Типы памяти в CUDA Самая быстрая – shared (on-chip) и регистры Самая медленная – глобальная (DRAM) Для ряда случаев можно использовать кэшируемую константную и текстурную память Доступ к памяти в CUDA идет отдельно для каждой половины warpа (half-warp)
15 2011 Работа с памятью в CUDA Основа оптимизации – оптимизация работы с памятью: Максимальное использование shared- памяти Использование специальных паттернов доступа к памяти, гарантирующих эффективный доступ – Паттерны работают независимо в пределах каждого half-warpа
16 2011 Работа с глобальной памятью в CUDA Пример работы с глобальной памятью float * devPtr; // pointer device memory // allocate device memory cudaMalloc ( (void **) &devPtr, 256*sizeof ( float ); // copy data from host to device memory cudaMemcpy ( devPtr, hostPtr, 256*sizeof ( float ), cudaMemcpyHostToDevice ); // process data // copy results from device to host cudaMemcpy ( hostPtr, devPtr, 256*sizeof( float ), cudaMemcpyDeviceToHost ); // free device memory cudaFree ( devPtr );
17 2011 Работа с глобальной памятью в CUDA Функции для работы с глобальной памятью cudaError_t cudaMalloc ( void ** devPtr, size_t size ); cudaError_t cudaMallocPitch ( void ** devPtr, size_t * pitch, size_t width, size_t height ); cudaError_t cudaFree ( void * devPtr ); cudaError_t cudaMemcpy ( void * dst, const void * src, size_t count, enum cudaMemcpyKind kind ); cudaError_t cudaMemcpyAsync ( void * dst, const void * src, size_t count, enum cudaMemcpyKind kind, cudaStream_t stream ); cudaError_t cudaMemset ( void * devPtr, int value, size_t count );
18 2011 Пример: умножение матриц Произведение двух квадратных матриц A и B размера N*N, N кратно 16 Матрицы расположены в глобальной памяти По одной нити на каждый элемент произведения 2D блок – 16*16 2D grid
19 2011 Умножение матриц. Простейшая реализация. #define BLOCK_SIZE 16 __global__ void matMult ( float * a, float * b, int n, float * c ) { int bx = blockIdx.x; int by = blockIdx.y; int tx = threadIdx.x; int ty = threadIdx.y; float sum = 0.0f; int ia = n * BLOCK_SIZE * by + n * ty; int ib = BLOCK_SIZE * bx + tx; int ic = n * BLOCK_SIZE * by + BLOCK_SIZE * bx; for ( int k = 0; k < n; k++ ) sum += a [ia + k] * b [ib + k*n]; c [ic + n * ty + tx] = sum; }
20 2011 Умножение матриц. Простейшая реализация. int numBytes = N * N * sizeof ( float ); float * adev, * bdev, * cdev ; dim3 threads ( BLOCK_SIZE, BLOCK_SIZE ); dim3 blocks ( N / threads.x, N / threads.y); cudaMalloc ( (void**)&adev, numBytes );// allocate DRAM cudaMalloc ( (void**)&bdev, numBytes ); // allocate DRAM cudaMalloc ( (void**)&cdev, numBytes ); // allocate DRAM // copy from CPU to DRAM cudaMemcpy ( adev, a, numBytes, cudaMemcpyHostToDevice ); cudaMemcpy ( bdev, b, numBytes, cudaMemcpyHostToDevice ); matMult >> ( adev, bdev, N, cdev ); cudaThreadSynchronize(); cudaMemcpy ( c, cdev, numBytes, cudaMemcpyDeviceToHost ); // free GPU memory cudaFree ( adev ); cudaFree ( bdev ); cudaFree ( cdev );
21 2011 Простейшая реализация. На каждый элемент – 2*N арифметических операций – 2*N обращений к глобальной памяти Memory bound (тормозит именно доступ к памяти)
22 2011 Используем CUDA Profiler Основное время (84.15%) ушло на чтение из глобальной памяти Вычисления заняли всего около 10%
23 2011 Оптимизация работы с глобальной памятью. Обращения идут через 32/64/128- битовые слова При обращении к t[i] – sizeof(t [0]) равен 4/8/16 байтам – t [i] выровнен по sizeof ( t [0] ) Вся выделяемая память всегда выровнена по 256 байт
24 Использование выравнивания. struct vec3 { float x, y, z; }; struct __align__(16) vec3 { float x, y, z; }; Размер равен 12 байт Элементы массива не будут выровнены в памяти Размер равен 16 байт Элементы массива всегда будут выровнены в памяти
25 2011 Объединение запросов к глобальной памяти. GPU умеет объединять ряд запросов к глобальной памяти в один блок (транзакцию) Независимо происходит для каждого half-warpа Длина блока должна быть 32/64/128 байт Блок должен быть выровнен по своему размеру
26 2011 Объединение (coalescing) для GPU с CC 1.2/1.3 Нити обращаются к – 8-битовым словам, дающим один 32- байтовый сегмент – 16-битовым словам, дающим один 64- байтовый сегмент – 32-битовым словам, дающим один 128- байтовый сегмент Получающийся сегмент выровнен по своему размеру
27 2011 Объединение (coalescing) Если хотя бы одно условие не выполнено – 1.2/1.3 – объединяет их в блоки (2,3,…) и для каждого блока проводится отдельная транзакция
28 2011 Объединение (coalescing) Можно добиться заметного увеличения скорости работы с памятью Лучше использовать не массив структур, а набор массивов отдельных компонент – это позволяет использовать coalescing
29 2011 Использование отдельных массивов struct vec3 { float x, y, z; }; vec3 * a; float x = a [threadIdx.x].x; float y = a [threadIdx.x].y; float z = a [threadIdx.x].z; float * ax, * ay, * az; float x = ax [threadIdx]; float y = ay [threadIdx]; float z = az [threadIdx]; Не можем использовать coalescing при чтении данных Поскольку нити одновременно обращаются к последовательно лежащим словам памяти, то будет происходить coalescing
30 2011 Ресурсы нашего курса Steps3d.Narod.Ru Google Site CUDA.CS.MSU.SU Google Group CUDA.CS.MSU.SU Google Mail CS.MSU.SU Google SVN Tesla.Parallel.Ru Twirpx.Com Nvidia.Ru
31 2011
32 Дополнительные слайды
33 2011 Объединение (coalescing) для GPU с CC 1.0/1.1 Нити обращаются к – 32-битовым словам, давая 64-байтовый блок – 64-битовым словам, давая 128-байтовый блок Все 16 слов лежат в пределах блока k-ая нить half-warpа обращается к k- му слову блока
34 2011 Объединение (coalescing) для GPU с CC 1.0/1.1 Coalescing
35 Объединение (coalescing) для GPU с CC 1.0/1.1 No Coalescing
36 2011 Объединение (coalescing) Если хотя бы одно условие не выполнено – 1.0/1.1 – 16 отдельных транзакций Для 1.0/1.1 порядок в котором нити обращаются к словам внутри блока имеет значения (в отличии от 1.1/1.3)
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.