Презентация GPU 1 - Томский политехнический университет

advertisement
Технологии высокопроизводительных
вычислений на GPU и гибридных
вычислительных системах
Томский политехнический университет
Аксёнов Сергей Владимирович
к.т.н., доцент каф.ОСУ ТПУ
Преимущества и недостатки SISD архитектуры
Преимущества
Недостатки
Последовательное исполнение
инструкций
Применение конвейеров
Общая память данных
Кэширование обращений к
памяти
Применение отработанных
оптимизирующих компиляторов
Блочное чтение памяти
Программирование е требует
особых знаний об архитектуре
Невозможность наращивания
тактовой частоты современных
CPU
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
2
GPU (Graphics Processing Unit) архитектура VS
SMP
Простые АЛУ, имеющие
общую память
Кэш и многофункциональные АЛУ
Преимущества GPU: Однократная систематическая задержка
между потоком исходных данных и результатов.
Недостаток GPU: Тщательная разработка алгоритма на
управляющих элементах
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
3
GPU: Основные положения
Является сопроцессором к CPU
Обладает собственной памятью
Обладает возможностью параллельного выполнения огромного
числа нитей
Отличия между нитями на CPU и GPU:
1.Создание, управление и удаление нитей на GPU –
низкозатратный процесс. Те же самые операции с нитями на CPU
достаточно ресурсоёмки.
2.Число нитей на CPU зависит от числа ядер и крайне мало,
количество нитей на GPU достаточно большое (несколько тысяч
или десятков тысяч)
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
4
Работа с нитями GPU
GPU обладает рядом потоковых мультипроцессоров (Streaming
Multiprocessor), каждый из которых способен одновременно
выполнять 768 (1024) нитей. Все мультипроцессоры работают
независимо друг от друга.
Нити разбиваются на группы по 32 нити (warp ). Нити в пределах
каждой группы выполняются физически одновременно.
Нити в разных группах могут находится на разных стадиях
выполнения программ.
Управление группой выполняет GPU.
Обычно каждой нити соответствует один элемент вычисляемых
данных.
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
5
Иерархия нитей в CUDA
Ядро – функция, которая выполняется каждой нитью
Верхний уровень иерархии – сетка (все нити, выполняющие
ядро).
Верхний уровень – одномерный или двухмерный массив блоков.
Каждый блок – 1D, 2D или 3D массив нитей.
Все блоки обладают одинаковой размерностью и размером.
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
6
Встроенные переменные CUDA
threadIdx – Идентификатор нити в блоке
blockIdx – Идентификатор блока в сетке
gridDim – размер сетки (количество блоков в сетке)
blockDim – размер блока (количество нитей в блоке)
Пример (для одномерного случая)
int globalIdx = threadIdx.x+blockIdx.x*blockDim.x;
Указанные переменные – трехмерный целочисленный вектор.
Доступны только для функций, выполняемых на GPU.
Разбиение нитей на группы происходит отдельно для каждого
блока. Нити могут взаимодействовать между собой только в
пределах блока.
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
7
Пример ядра: сложение 1D массивов
__global__ void sumOfVectors(float *a, float *b, float *c)
{
int index = blockIdx.x*blockDim.x + threadIdx.x;
c[index] = a[index] + b[index];
}
Каждая нить находит вычисляет только один элемент массива с.
Index определяет номер нити и индекс вычисляемого элемента
массива.
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
8
Взаимодействие нитей внутри блока
Разделяемая память (быстрая память 16Кбайт, которую нити
блока могут совместно использовать).
Барьерная синхронизация (синхронизация нитей блока). Вызов
функции __synchthreads(). Блокировка вызывающих нитей блока
до тех пор, пока все нити не войдут в эту функцию.
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
9
Спецификаторы функций
Квалификатор
Выполняется на
Вызывается на
__device__
device
device
__host__
host
host
__global__
device
host
__global__ определяет ядро и эту функция возвращает результат
void
Невозможно взять адрес __device__ функции
Функции, выполняемые на устройстве, не допускают рекурсию,
объявление статических переменных
Пример
__global__ void KernelFunction(float a)
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
10
Структура CUDA-программы
1. Выделение памяти на GPU
2. Копирование данных из RAM в выделенную память GPU
3. Запуск ядра
4. Копирование результатов из памяти GPU в RAM
5. Освобождение памяти GPU
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
11
Выделение и освобождение памяти GPU
Выделение памяти на GPU
cudaMalloc(void ** devPtr, size_t size)
devPtr – Указатель на память
size – Размер выделяемой памяти в байтах
Освобождение памяти GPU
cudaFree(void *devPtr)
devPtr – Указатель на память для освобождения
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
12
Копирование данных из RAM в память GPU и
обратно
cudaMemcpy(void *dest,
cudaMemcpyKind kind)
const
void
*src,
size_t
size,
enum
dest – Адрес памяти приёма данных
src – Адрес памяти отправления данных
size – Размер кипируемых данных в байтах
kind – Направление копирования {cudaMemcpyHostToHost,
cudaMemcpyHostToDevice,
cudaMemcpyDeviceToHost,
cudaMemcpyDeviceToDevice}.
Примеры
cudaMemcpy(aDev, aRAM, 1024, cudaMemcpyHostToDevice);
cudaMemcpy(bRAM, cDev, 2048, cudaMemcpyDeviceToHost);
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
13
Вызов ядра
kernelName<<<dim3 Dg, dim3 Db[, size_t Ns, cudaStream_t S]>>>(args)
kernelName – Имя __global__ функции.
Dg – размерность и размер сетки в блоках
Db – размерность и размер блока в нитях
Ns – размер дополнительно выделяемой разделяемой памяти
(опционально)
S- поток СUDA, в котором должен произойти вызов, по умолчанию
используется поток 0 (опционально).
args – список аргументов функции kernelName
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
14
Пример программы GPU для сложения двух
векторов: начало
__global__ void sumOfVectors(float *a, float *b, float *c)
{
int index = blockIdx.x*blockDim.x + threadIdx.x;
c[index] = a[index] + b[index];
}
void main(float *a, float *b, float *c)
{
int numBytes = n*sizeof(float);
float *aDev, *bDev, *cDev;
cudaMalloc((void**)&aDev, numBytes);
cudaMalloc((void**)&bDev, numBytes);
cudaMalloc((void**)&cDev, numBytes);
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
15
Пример программы GPU для сложения двух
векторов: окончание
//Определение конфигурации сетки
dim3 threads = dim3(512, 1);
dim3 blocks = dim3(n/threads.x, 1);
cudaMemcpy(aDev, a, numBytes, cudaMemcpyHostToDevice);
cudaMemcpy(bDev, b, numBytes, cudaMemcpyHostToDevice);
sumOfVectors<<<blocks, threads>>>(aDev, bDev, cDev);
cudaMemcpy(c, cDev, numBytes, cudaMemcpyDeviceToHost);
cudaFree(aDev);
cudaFree(bDev);
cudaFree(cDev);
}
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
16
Получение информации о GPU
#include <stdio.h>
int main ( int argc, char * argv [] )
{
int
deviceCount;
cudaDeviceProp devProp;
cudaGetDeviceCount ( &deviceCount ); // Определение числа устройств GPU
printf ( "Found %d devices\n", deviceCount );
for ( int device = 0; device < deviceCount; device++ )
{
cudaGetDeviceProperties ( &devProp, device );// Получение характеристик GPU
}
}
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;
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 1
17
Download