21
Архитектура и программирование Архитектура и программирование потоковых многоядерных процессоров для научных расчётов для научных расчётов Лекция 5. Пример вычислительного ядра задача умножения матриц Текстуры задача умножения матриц. Текстуры. Атомарные функции. Библиотека CUTIL

Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Embed Size (px)

DESCRIPTION

Слайды лекции курса "Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов".

Citation preview

Page 1: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Архитектура и программирование Архитектура и программирование потоковых многоядерных процессоров

для научных расчётовдля научных расчётов

Лекция 5. Пример вычислительного ядра – задача умножения матриц Текстуры – задача умножения матриц. Текстуры. Атомарные функции. Библиотека CUTIL

Page 2: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Процедура разработки программыПроцедура разработки программы

Общий подход к програмированию Разбить задачу на элементарные блоки данных, над которыми выполняется стандартный алгоритм обработки (единый для

б )всех блоков)

Разбить за-/вы- гружаемые данные на элементарные непересекающиеся блоки которые каждый из процессов непересекающиеся блоки, которые каждый из процессов прочтёт/запишет

Определить конфигурацию грида/блока позволяющее Определить конфигурацию грида/блока, позволяющее Оптимальное размещение промежуточных данных в регистрах и общей памятиОптимальную вычислительную загрузку потоковых процессоров

Определить график когерентного обращения к памяти процессами при загрузке данных

Page 3: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Вычислительная конфигурация Вычислительная конфигурация GPU

Процессы объединяются в блоки (blocks), внутри которых они имеют общую

Host Device

Grid 1р щу

память (shared memory) и синхронное исполнение

Kernel 1

Block(0, 0)

Block(1, 0)

Block(2, 0)

Block(0 1)

Block(1 1)

Block(2 1)

Блоки объединяются в сетки (grids)

Нет возможности предсказать очерёдность запуска блоков в Kernel

(0, 1) (1, 1) (2, 1)

Grid 2

очерёдность запуска блоков в сеткиМежду блоками нет и не может быть (см. выше) общей памяти

2

Block (1, 1)

Thread(0, 1)

Thread(1, 1)

Thread(2, 1)

Thread(3, 1)

Thread(4, 1)

Thread(0, 0)

Thread(1, 0)

Thread(2, 0)

Thread(3, 0)

Thread(4, 0)

( ) ( ) ( ) ( ) ( )

Thread(0, 2)

Thread(1, 2)

Thread(2, 2)

Thread(3, 2)

Thread(4, 2)

Page 4: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Пример программы для GPUПример программы для GPUумножение матриц -1

bx

tx

0 1 2

Разбить задачу на элементарные блоки данных, над которыми выполняется стандартный алгоритм обработки

N

tx01 bsize-12

WID

TH

стандартный алгоритм обработки (единый для всех блоков)Каждый блок вычисляет некоторую небольшую область результата

BL

OC

K_W

WID

TH H

b

у р уКаждый тред в блоке вычисляет один элемент этой области

M P

BL

OC

K_W

Psub210

0

SIZE

BLOCK WIDTHBLOCK WIDTHBLOCK WIDTH

byty

2

bsize-1

1

BL

OC

K_S Ha

BLOCK_WIDTH

WbWa

BLOCK_WIDTHBLOCK_WIDTH

2

Page 5: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Пример программы для GPUПример программы для GPUумножение матриц -2

bx

tx

0 1 2

Разбить данные на элементарные блоки (непересекающиеся), которые каждый из процессов прочтёт/запишет

N

tx01 bsize-12

WID

TH

процессов прочтёт/запишетНеобходимые области исходных матриц разбиваются на квадратные областиКаждый из тредов читает один элемент из этих

BL

OC

K_W

WID

TH H

b

Каждый из тредов читает один элемент из этих областей в разделяемую память

M P

BL

OC

K_W

Psub210

0

SIZE

BLOCK WIDTHBLOCK WIDTHBLOCK WIDTH

byty

2

bsize-1

1

BL

OC

K_S Ha

BLOCK_WIDTH

WbWa

BLOCK_WIDTHBLOCK_WIDTH

2

Page 6: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Пример программы для GPUПример программы для GPUумножение матриц -3

bx

tx

0 1 2

Определить конфигурацию грида/блока, позволяющее

Оптимальное размещение промежуточных N

tx01 bsize-12

WID

TH

Оптимальное размещение промежуточных данных в регистрах и общей памятиОптимальную вычислительную загрузкупотоковых процессоров

BL

OC

K_W

WID

TH H

b

Блок = 16x16= 256 тредов больше чем 192, меньше чем 512 M P

BL

OC

K_W

Целое количество варпов в блоке

Psub210

0

SIZE

Размеры грида определяются размерами исходных матриц

BLOCK WIDTHBLOCK WIDTHBLOCK WIDTH

byty

2

bsize-1

1

BL

OC

K_S Ha

BLOCK_WIDTH

WbWa

BLOCK_WIDTHBLOCK_WIDTH

2

Page 7: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Пример программы для GPUПример программы для GPUумножение матриц -4

bx

tx

0 1 2

Размер разделяемой памяти = 16KB на мультипроцессор (максимальное

б )N

tx01 bsize-12

WID

TH

количество памяти для блока)В разделяемую память мультипроцессора поместятся данные от 8 блоков

BL

OC

K_W

WID

TH H

b

M P

BL

OC

K_W

Регистровая память расходуется

Psub210

0

SIZE

расходуется незначительно

Для определения

BLOCK WIDTHBLOCK WIDTHBLOCK WIDTH

byty

2

bsize-1

1

BL

OC

K_S Haколичества регистров,

приходящееся на один тред нужно смотреть PTX код

BLOCK_WIDTH

WbWa

BLOCK_WIDTHBLOCK_WIDTH

2

Page 8: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Хост-функция Хост функция умножения матриц

#define BLOCK SIZE 16 #define BLOCK_SIZE 16 __global__ void Muld(float*, float*, int, int, float*); void Mul(const float* A, const float* B, int hA, int wA, int wB, float* C) { int size; // L d A d B t th d i// Load A and B to the devicefloat* Ad; size = hA * wA * sizeof(float); cudaMalloc((void**)&Ad, size); cudaMemcpy(Ad, A, size, cudaMemcpyHostToDevice); float* Bd; size = wA * wB * sizeof(float); cudaMalloc((void**)&Bd, size); cudaMemcpy(Bd, B, size, cudaMemcpyHostToDevice); // Allocate C on the device float* Cd; size = hA * wB * sizeof(float); cudaMalloc((void**)&Cd, size); // Compute the execution configuration assuming the matrix dimensions are multiples of BLOCK_SIZE dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE); dim3 dimGrid(wB / dimBlock.x, hA / dimBlock.y); // Launch the device computation Muld<<<dimGrid, dimBlock>>>(Ad, Bd, wA, wB, Cd); // Read C from the device cudaMemcpy(C, Cd, size, cudaMemcpyDeviceToHost); // Free device memory cudaFree(Ad); cudaFree(Bd); cudaFree(Cd); }

Page 9: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

GPU ядро умножения матрицGPU ядро умножения матриц

global void Muld(float* A float* B int wA int wB float* C) {__global__ void Muld(float* A, float* B, int wA, int wB, float* C) {

int bx = blockIdx.x; // Block indexint by = blockIdx.y; i t t th dId // Th d i d int tx = threadIdx.x; // Thread index int ty = threadIdx.y; int aBegin = wA * BLOCK_SIZE * by; // Index of the first sub-matrix of A processed by the blockint aEnd = aBegin + wA - 1; // Index of the last sub-matrix of A processed by the blockint aStep = BLOCK_SIZE; // Step size used to iterate through the sub-matrices of A int bBegin = BLOCK_SIZE * bx; // Index of the first sub-matrix of B processed by the blockint bStep = BLOCK_SIZE * wB; // Step size used to iterate through the sub-matrices of Bfloat Csub = 0; // The element of the block sub-matrix that is computed by the thread

for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep) { // Shared memory for the sub-matrix of A__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];

// Shared memory for the sub-matrix of B__shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];

Page 10: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

GPU ядро умножения матрицGPU ядро умножения матриц(продолжение)

As[ty][tx] = A[a + wA * ty + tx]; // Load the matrices from global memory to shared memory;Bs[ty][tx] = B[b + wB * ty + tx]; // each thread loads one element of each matrix __syncthreads(); // Synchronize to make sure the matrices are loadedy () y

// Multiply the two matrices together; // each thread computes one element // of the block sub-matrix//for (int k = 0; k < BLOCK_SIZE; ++k)

Csub += As[ty][k] * Bs[k][tx];

// Synchronize to make sure that the preceding // Synchronize to make sure that the preceding // computation is done before loading two new // sub-matrices of A and B in the next iteration__syncthreads(); } } // Write the block sub-matrix to global memory; // each thread writes one element int c = wB * BLOCK_SIZE * by + BLOCK_SIZE * bx; C[c + wB * ty + tx] = Csub; C[c + wB * ty + tx] = Csub; }

Page 11: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Уровень производительностиУровень производительности

Для матрицы 1024*1024 Автоматическое распределение : 3.0 сек - 45 GFLOPS1 блок на SM : 3.6 сек. - 35 GFLOPS2 блока на SM : 3.0 сек. - 45 GFLOPSОчевидно ограничивающим фактором является Очевидно, ограничивающим фактором является требование запуска 2 блоков на SM, а не ограничение по разделяемой памяти (8 блоков на SM)

Развёртывание циклов помогает (развёрнуто 16 раз)Развернутая программа (автомат) : 1.6 сек. - 80 GFLOPS1 блок на SM : 2.1 сек. - 61 GFLOPS2 блока на SM : 1.6 сек. - 80 GFLOPS

Page 12: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Уровень производительностиУровень производительности(продолжение)

Возможный альтернативный график вычислений

Loop { Load to Shared MemoryLoop {

Load to Shared Memory

Load to Shared MemorySyncthread()

y

Syncthread()Loop {

C bbl kCompute current subblock

Compute current subblockLoad to Shard Memory

Syncthreads()}

Syncthreads()}} }

Page 13: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Texture Processor Cluster (TPC)Texture Processor Cluster (TPC)

TEX Т й б TPC

TEX – Текстурный блок – логика адресации текстурных массивов в 1D, 2D, 3D

+ L1 Кэш Текстур

Tex T

SM 0

Shared Memory

Instruction Fetch

Instruction L 1 Cache

Instruction Decode

I+ L1 Кэш Текстур

L2 Кэш инструкций и данных для обоих SM

ture

extu

SP 0 R

SP 1 R

SP 2 R

SP 3 R

SP 4R

SP 5R

SP 6R

SP 7R

SFU

SFU

&D

L SM

x2 Потоковых Мультипроцессора (Streaming Multiprocessor)

L1

re

U

SM 1Instruction Fetch

Instruction L 1 Cache

I t ti D d

Constant L 1 Cache 2

Ca (St ea g u t p ocesso )

x8 потоковых процессоров (streaming processors) = 8 MAD/clock cycleРегистры для хранения промежуточных

Cach

nit

SP 0 R

SP 1 R

SP 2 R

SP 4R

SP 5R

SP 6R

Shared Memory

SFU

SFU

Instruction Decode

che

р р р урезультатов у выполняемых тредов => больше тредов лучше скрыты операции чтения, но межет не хватить регистров

e

Load/Store

SP 3 R SP 7R

Constant L 1 Cache

Page 14: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Использование текстурИспользование текстур(обзор)

Текстуры - удобный способ обращения с табличными исходными даннымиК 2 SM б й L1 б й L2Кэшированы – для каждых 2-х SM – общий L1 кэш, общий L2кэш для всего кристалла

Замена разделяемой памяти для RO операндовН ё б й Нет жёстких требований к правильности адресации

Адреса – числа с плавающей точкой (возможно с нормализацией)

Позволяют выделять объекты с адресом, находящимся между табличными значениями

Аппоксимация ближайшимЛ й б й ( й Линейная и билинейная аппроксимация (исходя из значений соседей)

Варианты “tile” и “center”Поведение текстуры при выходе адреса за пределы сеткиПоведение текстуры при выходе адреса за пределы сетки

Page 15: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Использование текстур Использование текстур (детали)

Объявление вне тела функции - texture<Type, Dim, ReadMode> texRef;Type = типDim = 1 | 2Dim 1 | 2ReadMode = cudaReadModeNormalizedFloat | CudaReadModeElementType

Определение – привязывание объявленной ссылки на 1D (линейный массив) или 2D (CudaArray) объекту в глобальной памяти или 2D (CudaArray) объекту в глобальной памяти

cudaBindTexture()cudaBindTextureToArray()cudaUnbindTexture()

Использование – “texture fetch”1D-массивTexture_type tex1Dfetch(texture<uchar4, 1, cudaReadModeNormalizedFloat> texRef,int x);2D-массивTexture_type tex1D(texture<Type, 1, readMode> texRef, float x); Texture_type tex2D(texture<Type, 2, readMode> texRef, float x, float y);

Page 16: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Использование текстур Использование текстур (пример часть 1)

texture<float, 2, cudaReadModeElementType> tex; // declare texture reference for 2D float texture__global__ void transformKernel( float* g_odata, int width, int height, float theta) {

// calculate normalized texture coordinatesunsigned int x = blockIdx.x*blockDim.x + threadIdx.x;unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;

float u = x / (float) width;float v = y / (float) height;

u -= 0.5f; // transform coordinatesu 0.5f; // transform coordinatesv -= 0.5f;float tu = u*cosf(theta) - v*sinf(theta) + 0.5f;float tv = v*cosf(theta) + u*sinf(theta) + 0.5f;

// read from texture and write to global memoryg_odata[y*width + x] = tex2D(tex, tu, tv);

}

Page 17: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Использование текстур Использование текстур (пример часть 2)

// set texture parameterstex.addressMode[0] = cudaAddressModeWrap;tex.addressMode[1] = cudaAddressModeWrap;ptex.filterMode = cudaFilterModeLinear;tex.normalized = true; // access with normalized texture coordinates

// Bind the array to the texture// yCUDA_SAFE_CALL( cudaBindTextureToArray( tex, cu_array, channelDesc));

dim3 dimBlock(8, 8, 1);dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, 1);dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, 1);

// warmuptransformKernel<<< dimGrid, dimBlock, 0 >>>( d_data, width, height, angle);

CUDA_SAFE_CALL( cudaThreadSynchronize() );

// execute the kerneltransformKernel<<< dimGrid dimBlock 0 >>>( d data width height angle);transformKernel<<< dimGrid, dimBlock, 0 >>>( d_data, width, height, angle);

Page 18: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Обращение с памятью из ворпаОбращение с памятью из ворпа

НЕАТОМАРНЫЕ ИНСТРУКЦИИ (G80)ЕСЛИ какая-либо инструкция исполняемая ворпом пишет в одно место в глобальной или общей памяти ТО количество записей и их очерёдность недетерминированыОДНАКО по крайней мере одна запись состоится

АТОМАРНЫЕ ИНСТРУКЦИИ (G92+)ЕСЛИ какая-либо инструкция исполняемая ворпом пишет/читает/модифицирует одно место в глобальной памяти ТО их очерёдность записей недетерминированаОДНАКО все записи состоятся последовательно

Page 19: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Атомарные функцииАтомарные функции

Функции чтения/модификации/записи данных в глобальную память – основа построения алгоритмов стекового декодированияРаботают только с целыми значениями (!)Гарантируют неизменность операнда в процессе операцииоперации

Арифметические функции: atomicAdd,atomicSub, atomicExch, atomicMax, atomicInc, atomicDecatomicMax, atomicInc, atomicDec

int atomicAdd(int* address, int val);

Функция atomicCAS – Compare and store

int atomicCAS(int* address, int compare, int val);

Битовые функции atomicAnd, atomicOr, atomicXor int atomicAnd(int* address, int val);

Page 20: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Библиотека cutilБиблиотека cutil

Набор утилит для различных служебных целей (cut* - функции)Макросы типа CUDA_SAFE_CALL - различные ситуции, с синхронизацией без неё для эмуляциисинхронизацией, без неё, для эмуляцииУтилиты профайлинга

измерение длительности исполнения CUT SAFE CALL( cutCreateTimer( &timer));CUT_SAFE_CALL( cutCreateTimer( &timer));CUT_SAFE_CALL( cutStartTimer( timer)); CUT_SAFE_CALL( cutStopTimer( timer));CUT SAFE CALL( cutDeleteTimer(&timer));CUT_SAFE_CALL( cutDeleteTimer(&timer));Определение конфликтных ситуаций операций чтенияИ т.д. => см cutil.h

Находится в директории common в составе SDKНаходится в директории common в составе SDKВ отличии от других библиотек предоставляется в виде исходных текстовНеобходимо скомпилировать до работы над своим проектомНеобходимо скомпилировать до работы над своим проектом

Page 21: Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция

Итоги лекцииИтоги лекции

В результате лекции студенты должны :Получить практический пример составления вычислительного ядра для типовой задачи.Получить представление о свойствах текстур и возможности их применения в научных вычислениях

Получить представление о свойствах и возможности применения в научных вычислениях атомарных функций

Достаточные знания для начала самостоятельной работы