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

реклама
Технологии высокопроизводительных
вычислений на GPU и гибридных
вычислительных системах
Лекция 2
Томский политехнический университет
Аксёнов Сергей Владимирович
к.т.н., доцент каф.ОСУ ТПУ
Оценка времени исполнения ядра на GPU-1
cudaEventCreate(*cudaEvent_t event ) – создание события event
cudaEventRecord(cudaEvent_t, cudaStream stream) – привязка
события event к текущей позиции в потоке cudaStream
cudaEventSynchronize(cuda_Event_t event) – ожидание завершения
работы GPU. Синхронизация по событию event.
cudaEventElapsedTime(float * ms, cudaEvent_t start, cudaEvent_t
stop);
cudaEventDestroy(cudaEvent_t event) – Удаление события event
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
2
Оценка времени исполнения ядра на GPU-2
cudaEvent_t start, stop;
float gpu_time = 0;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
cudaKernel<<blocks, threads>>(args);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&gpu_time, start, stop);
printf(“Время исполнения ядра:%f мс.”,gpu_time);
cudaEventDestroy(start);
cudaEventDestroy(stop);
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
3
Иерархия памяти
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
4
Огранизация памяти в GPU
Тип памяти Расположение
Доступ
для GPU
Уровень
доступа
Время
жизни
Регистры
Мультипроцессор R/W
Нить
Нить
Локальная
DRAM
Нить
Нить
Разделяемая
Мультипроцессор R/W
Все нити
блока
Блок
Глобальная
DRAM
R/W
Все нити и
CPU
Выделяется
CPU
Константная
DRAM
R/O
Все нити и
CPU
Выделяется
CPU
Текстурная
DRAM
R/O
Все нити и
CPU
Выделяется
CPU
R/W
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
5
Оптимизация производительности
Для каждого потока можно оптимизировать:
 чтение операндов
 выполнение инструкции
 запись результата
Для повышения производительности необходимо:
уменьшить число арифметических инструкций с
низкой скоростью работы
максимизировать использование доступной
пропускной способности для каждого типа памяти
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
6
Производительность арифметических
инструкций
4 clock cycles:
 floating point сложение, умножение, умножение-сложение (multiply-add)
 integer сложение
 24-bit integer умножение (__mul24)
 побитовые операции, сравнение, минимум, максимум, преобразование
типов
16 clock cycles:
 вычисление обратного числа, 1 / sqrt(x), __logf(x)
 умножение 32-bit integers
Целочисленное деление и взятие остатка по модулю следует заменять
битовыми операциями везде, где это возможно.
32 clock cycles:
 sinf(x), __cosf(x), __expf(x) (доступны только из кода, выполняемого на
устройстве)
Рекомендуется использовать везде, где это возможно, floating point данные и
floating point версии арифметических функций
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
7
Пример использования константной памяти
__constant__ int maxValueDev;
__constant__ int dataDev[10];
__global__ void KernelFunction(int *a, int *b, int *c)
{
int index = blockIdx.x*blockDim.x + threadIdx.x;
if (a[index]>maxValueDev)
{
int factor = index % 10;
c[index] = a[index] * dataDev[factor] - b[index];
}
}
void main
{
…
int dataRAM[10];
for (int i=0; i<10; i++)
dataRAM[i] = i;
int maxValueRAM = 5;
cudaMemcpyToSymbol(dataDev, dataRAM, 10*sizeof(int), 0, cudaMemcpyHostToDevice);
cudaMemcpyToSymbol(&maxValueDev, &maxValueRAM, sizeof(int), 0, cudaMemcpyHostToDevice);
…
KernelFunction<<<blocks, threads>>>(dev_a, dev_b, dev_c);
…
}
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
8
Оптимизация работы с глобальной памятью:
выравнивание хранения данных
struct myStruct
{
float x; //4 bytes
short y; //2 bytes
int z; //4 bytes
};
//10 bytes
struct __align__(16) myStruct()
{
float x; //4 bytes
short y; //2 bytes
int z; //4 bytes
};
//10 bytes
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
9
Оптимизация работы с глобальной памятью:
Объединение запросов нитей полугруппы
Требования к объединению запросов нитей
полугруппы:
1.Все нити обращаются к 32 битовым словам (всего
обращения дают блок 64 байта) или все нити
обращаются к 64 битовым словам (блок обращения 128 байт).
2.Получившийся блок выровнен по своему размеру,
адрес блока 64 байта кратен 64, адрес блока 128 байт
кратен 128.
3.Все слова, к которым обращаются нити лежат в
пределах этого блока
4.Все нити обращаются последовательно.
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
10
Оптимизация работы с глобальной памятью:
Оптимум
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
11
Оптимизация работы с памятью: Не оптимально
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
12
Транспонирование матрицы: глобальная
память
__global__ void transposeMatrixSlow(float* inputMatrix, float*
outputMatrix, int width, int height)
{
int xIndex = blockDim.x * blockIdx.x + threadIdx.x;
int yIndex = blockDim.y * blockIdx.y + threadIdx.y;
if ((xIndex < width) && (yIndex < height))
{
//Линейный индекс элемента строки исходной матрицы
int inputIdx = xIndex + width * yIndex;
//Линейный индекс элемента столбца матрицы-результата
int outputIdx = yIndex + height * xIndex;
}
}
outputMatrix[outputIdx] = inputMatrix[inputIdx];
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
13
Оптимизация работы с разделяемой памятью:
Оптимум
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
14
Оптимизация работы с разделяемой памятью:
Не оптимально
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
15
Транспонирование матрицы: разделяемая память
__global__
void
transposeMatrixFast(float*
outputMatrix, int width, int height)
{
__shared__ float temp[BLOCK_DIM][BLOCK_DIM];
int xIndex = blockIdx.x * blockDim.x + threadIdx.x;
int yIndex = blockIdx.y * blockDim.y + threadIdx.y;
inputMatrix,
float*
if ((xIndex < width) && (yIndex < height))
{
int idx = yIndex * width + xIndex;
temp[threadIdx.y][threadIdx.x] = inputMatrix[idx];
}
__syncthreads();
xIndex = blockIdx.y * blockDim.y + threadIdx.x;
yIndex = blockIdx.x * blockDim.x + threadIdx.y;
if ((xIndex < height) && (yIndex < width))
{
int idx = yIndex * height + xIndex;
outputMatrix[idx] = temp[threadIdx.x][threadIdx.y];
}
}
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
16
Результаты: Транспонирование матрицы
2048 x 1536
Технологии высокопроизводительных вычислений на GPU и
гибридных вычислительных системах - Лекция 2
17
Скачать