SlideShare a Scribd company logo
1 of 21
Download to read offline
Архитектура и программирование
потоковых многоядерных процессоров
для научных расчётов

Лекция 5. Пример вычислительного ядра
– задача умножения матриц Текстуры
матриц. Текстуры.
Атомарные функции. Библиотека CUTIL
Процедура разработки программы
Общий подход к програмированию
Разбить задачу на элементарные блоки данных, над которыми
выполняется стандартный алгоритм обработки (единый для
всех б
блоков)
)
Разбить за-/вы- гружаемые данные на элементарные
непересекающиеся блоки которые каждый из процессов
блоки,
прочтёт/запишет
Определить конфигурацию грида/блока позволяющее
грида/блока,
Оптимальное размещение промежуточных данных в регистрах и общей
памяти
Оптимальную вычислительную загрузку потоковых процессоров

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

Device
Grid 1

Kernel
1

Block
(0, 0)

Block
(1, 0)

Block
(2, 0)

Block
(0,
(0 1)

Block
(1,
(1 1)

Block
(2,
(2 1)

Grid 2
Kernel
2

Block (1, 1)
Thread Thread Thread Thread Thread
(0, 0)
(1, 0)
(2, 0)
(3, 0)
(4, 0)
Thread Thread Thread Thread Thread
( )
(0, 1)
( )
(1, 1)
( )
(2, 1)
( )
(3, 1)
( )
(4, 1)
Thread Thread Thread Thread Thread
(0, 2)
(1, 2)
(2, 2)
(3, 2)
(4, 2)

Процессы объединяются в
блоки (blocks), внутри
которых они имеют общую
р
щу
память (shared memory) и
синхронное исполнение
Блоки объединяются в сетки
(grids)
Нет возможности предсказать
очерёдность запуска блоков в
сетки
Между блоками нет и не может
быть (см. выше) общей памяти
Пример программы для GPU
умножение матриц -1

bx

0

1

2

tx
BLOCK_W
WIDTH
BLOCK_W
WIDTH

Hb
Ha

M

N

BLOCK_S
SIZE

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

bsize-1

012

P

0

by

0
1
2
1

ty

Psub

bsize-1
BLOCK_WIDTH
BLOCK WIDTH
BLOCK_WIDTH
BLOCK WIDTH

BLOCK_WIDTH
BLOCK WIDTH

Wa

Wb

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

bx

0

1

2

tx
BLOCK_W
WIDTH
BLOCK_W
WIDTH

Hb
Ha

M

N

BLOCK_S
SIZE

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

bsize-1

012

P

0

by

0
1
2
1

ty

Psub

bsize-1
BLOCK_WIDTH
BLOCK WIDTH
BLOCK_WIDTH
BLOCK WIDTH

BLOCK_WIDTH
BLOCK WIDTH

Wa

Wb

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

bx

0

1

2

tx

Hb
Ha

M

BLOCK_W
WIDTH
BLOCK_W
WIDTH

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

N

BLOCK_S
SIZE

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

bsize-1

012

P

0

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

0
1
2

by

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

ty

Psub

bsize-1
BLOCK_WIDTH
BLOCK WIDTH
BLOCK_WIDTH
BLOCK WIDTH

BLOCK_WIDTH
BLOCK WIDTH

Wa

Wb

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

bx

0

1

2

tx

Hb
Ha

M

BLOCK_W
WIDTH
BLOCK_W
WIDTH

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

N

BLOCK_S
SIZE

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

bsize-1

012

P

0

Для определения
количества регистров,
by
приходящееся на один 1
тред нужно смотреть
PTX код

0
1
2

ty

Psub

bsize-1
BLOCK_WIDTH
BLOCK WIDTH
BLOCK_WIDTH
BLOCK WIDTH

BLOCK_WIDTH
BLOCK WIDTH

Wa

Wb

2
Хост функция
Хост-функция
умножения матриц
#define BLOCK SIZE 16
BLOCK_SIZE
__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;
// Load A and B t the device
L d
d to th d i
float* 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); }
GPU ядро умножения матриц
__global__ void Muld(float* A, float* B, int wA, int wB, float* C) {
global
A
B
wA
wB
int bx = blockIdx.x; // Block index
int by = blockIdx.y;
int tx
i t t = threadIdx.x; // Thread index
th
dId
Th
di d
int ty = threadIdx.y;
int aBegin = wA * BLOCK_SIZE * by; // Index of the first sub-matrix of A processed by the block
int aEnd = aBegin + wA - 1; // Index of the last sub-matrix of A processed by the block
int 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 block
int bStep = BLOCK_SIZE * wB; // Step size used to iterate through the sub-matrices of B
float 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];
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 loaded
y
()
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
// 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;
}
Уровень производительности
Для матрицы 1024*1024
Автоматическое распределение : 3.0 сек - 45 GFLOPS
1 блок на SM
: 3.6 сек. - 35 GFLOPS
2 блока на SM
: 3.0 сек. - 45 GFLOPS
Очевидно,
Очевидно ограничивающим фактором является
требование запуска 2 блоков на SM, а не ограничение
по разделяемой памяти (8 блоков на SM)
Развёртывание циклов помогает (развёрнуто 16 раз)
Развернутая программа (автомат) : 1.6 сек. - 80 GFLOPS
1 блок на SM
: 2.1 сек. - 61 GFLOPS
2 блока на SM
: 1.6 сек. - 80 GFLOPS
Уровень производительности
(продолжение)
Возможный альтернативный график вычислений

Loop {
Load to Shared Memory
y
Syncthread()

Load to Shared Memory
Syncthread()
Loop {

Compute current subblock

Compute current subblock
C
bbl k
Load to Shard Memory

Syncthreads()
}

Syncthreads()
}
Texture Processor Cluster (TPC)
TPC
SM 0
Instruction Fetch

T

Instruction L

e

1 Cache

Instruction Decode

x

T

t

e

u

x

I

Shared Memory
SP 0

R

SP 1

R

R

SP 5

SP 2

R

R

SP 6

R

R

SP 7

F

r

t

e

u

U

L

S

D

F

Constant L

r

&

SP 4

SP 3

S

R

e

U

L

1 Cache

2

SM 1

1

C

Instruction Fetch
Instruction L

U

1 Cache

a

Instruction Decode
I t
ti D
d

C

n

a

i

c

t

h
e

c

Shared Memory
SP 0

S

R

R

SP 1

R

R

SP 5

h

SP 4

F
U

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

S
F

SP 2

R

R

SP 6

SP 3

R

R

SP 7

Constant L

1 Cache

Load/Store

U

e

L2 Кэш инструкций и данных для обоих
SM
x2 Потоковых Мультипроцессора
(St ea
(Streaming Multiprocessor)
g u t p ocesso )
x8 потоковых процессоров (streaming
processors) = 8 MAD/clock cycle
Регистры для хранения промежуточных
р
р
р
у
результатов у выполняемых тредов =>
больше тредов лучше скрыты операции
чтения, но межет не хватить регистров
Использование текстур
(обзор)
Текстуры - удобный способ обращения с табличными
исходными данными
Кэшированы – для каждых 2 SM – общий L1 кэш, общий L2
К
2-х
б
й
б
й
кэш для всего кристалла
Замена разделяемой памяти для RO операндов
Нет ё
Н жёстких требований к правильности адресации
б
й

Адреса – числа с плавающей точкой (возможно с
нормализацией)
Позволяют выделять объекты с адресом, находящимся между
табличными значениями
Аппоксимация ближайшим
Линейная и билинейная аппроксимация (
Л
й
б
й
(исходя из значений
й
соседей)

Варианты “tile” и “center”
Поведение текстуры при выходе адреса за пределы сетки
Использование текстур
(детали)
Объявление вне тела функции - texture<Type, Dim, ReadMode> texRef;
Type = тип
Dim = 1 | 2
ReadMode = cudaReadModeNormalizedFloat | CudaReadModeElementType

Определение – привязывание объявленной ссылки на 1D (линейный массив)
или 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);
Использование текстур
(пример часть 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 coordinates
unsigned 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 -=
v -=
float
float

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

// read from texture and write to global memory
g_odata[y*width + x] = tex2D(tex, tu, tv);
}
Использование текстур
(пример часть 2)
// set texture parameters
tex.addressMode[0] = cudaAddressModeWrap;
tex.addressMode[1] = cudaAddressModeWrap;
p
tex.filterMode = cudaFilterModeLinear;
tex.normalized = true; // access with normalized texture coordinates
// Bind the array to the texture
y
CUDA_SAFE_CALL( cudaBindTextureToArray( tex, cu_array, channelDesc));
dim3 dimBlock(8, 8, 1);
dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, 1);
// warmup
transformKernel<<< dimGrid, dimBlock, 0 >>>( d_data, width, height, angle);
CUDA_SAFE_CALL( cudaThreadSynchronize() );
// execute the kernel
transformKernel<<< dimGrid dimBlock 0 >>>( d data width, height, angle);
dimGrid, dimBlock,
d_data, width height
Обращение с памятью из ворпа
НЕАТОМАРНЫЕ ИНСТРУКЦИИ (G80)
ЕСЛИ какая-либо инструкция исполняемая ворпом пишет в одно
место в глобальной или общей памяти
ТО количество записей и их очерёдность недетерминированы
ОДНАКО по крайней мере одна запись состоится

АТОМАРНЫЕ ИНСТРУКЦИИ (G92+)
ЕСЛИ какая-либо инструкция исполняемая ворпом
пишет/читает/модифицирует одно место в глобальной памяти
ТО их очерёдность записей недетерминирована
ОДНАКО все записи состоятся последовательно
Атомарные функции
Функции чтения/модификации/записи данных в глобальную
память – основа построения алгоритмов стекового
декодирования
Работают только с целыми значениями (!)
Гарантируют неизменность операнда в процессе
операции
Арифметические функции: atomicAdd,atomicSub, atomicExch,
atomicMax, 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);
Библиотека cutil
Набор утилит для различных служебных целей (cut* - функции)
Макросы типа CUDA_SAFE_CALL - различные ситуции, с
синхронизацией,
синхронизацией без неё для эмуляции
неё,
Утилиты профайлинга
измерение длительности исполнения
CUT_SAFE_CALL(
CUT SAFE CALL( cutCreateTimer( &timer));
CUT_SAFE_CALL( cutStartTimer( timer));
CUT_SAFE_CALL( cutStopTimer( timer));
CUT_SAFE_CALL(
CUT SAFE CALL( cutDeleteTimer(&timer));
Определение конфликтных ситуаций операций чтения
И т.д. => см cutil.h
Находится в директории common в составе SDK
В отличии от других библиотек предоставляется в виде исходных
текстов
Необходимо скомпилировать до работы над своим проектом
Итоги лекции
В результате лекции студенты должны :
Получить практический пример составления
вычислительного ядра для типовой задачи.
Получить представление о свойствах текстур и
возможности их применения в научных вычислениях
Получить представление о свойствах и возможности
применения в научных вычислениях атомарных функций

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

More Related Content

What's hot

Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Ontico
 
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Ontico
 
CUDA Course 2010 at MSU
CUDA Course 2010 at MSUCUDA Course 2010 at MSU
CUDA Course 2010 at MSUlarhat
 
Introduction in CUDA (1-3)
Introduction in CUDA (1-3)Introduction in CUDA (1-3)
Introduction in CUDA (1-3)Alexander Mezhov
 
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...Ontico
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Mikhail Kurnosov
 
Валентин Коновалов "Кэш МЯК"
Валентин Коновалов "Кэш МЯК"Валентин Коновалов "Кэш МЯК"
Валентин Коновалов "Кэш МЯК"Yandex
 
Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)
Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)
Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)Ontico
 
Вячеслав Бирюков - Как Linux работает с памятью
Вячеслав Бирюков - Как Linux работает с памятьюВячеслав Бирюков - Как Linux работает с памятью
Вячеслав Бирюков - Как Linux работает с памятьюYandex
 
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...Ontico
 
Хранение данных на виниле / Константин Осипов (tarantool.org)
Хранение данных на виниле / Константин Осипов (tarantool.org)Хранение данных на виниле / Константин Осипов (tarantool.org)
Хранение данных на виниле / Константин Осипов (tarantool.org)Ontico
 
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...Mikhail Kurnosov
 
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...rit2011
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыAlexey Paznikov
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Mikhail Kurnosov
 
Кластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможностиКластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможностиAlexey Demidchuk
 

What's hot (19)

Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
 
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
 
CUDA Course 2010 at MSU
CUDA Course 2010 at MSUCUDA Course 2010 at MSU
CUDA Course 2010 at MSU
 
Introduction in CUDA (1-3)
Introduction in CUDA (1-3)Introduction in CUDA (1-3)
Introduction in CUDA (1-3)
 
CUDA Best Practices (2-3)
CUDA Best Practices (2-3)CUDA Best Practices (2-3)
CUDA Best Practices (2-3)
 
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
Отказоустойчивая обработка 10M OAuth токенов на Tarantool / Владимир Перепели...
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
 
Валентин Коновалов "Кэш МЯК"
Валентин Коновалов "Кэш МЯК"Валентин Коновалов "Кэш МЯК"
Валентин Коновалов "Кэш МЯК"
 
Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)
Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)
Использование очередей асинхронных сообщений с PostgreSQL (Илья Космодемьянский)
 
Вячеслав Бирюков - Как Linux работает с памятью
Вячеслав Бирюков - Как Linux работает с памятьюВячеслав Бирюков - Как Linux работает с памятью
Вячеслав Бирюков - Как Linux работает с памятью
 
1508 10035
1508 100351508 10035
1508 10035
 
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
 
Хранение данных на виниле / Константин Осипов (tarantool.org)
Хранение данных на виниле / Константин Осипов (tarantool.org)Хранение данных на виниле / Константин Осипов (tarantool.org)
Хранение данных на виниле / Константин Осипов (tarantool.org)
 
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...Использование Time-Stamp Counter для измерения времени выполнения кода  на пр...
Использование Time-Stamp Counter для измерения времени выполнения кода на пр...
 
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...
 
введение в Gpu
введение в Gpuвведение в Gpu
введение в Gpu
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
 
Кластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможностиКластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможности
 

Similar to Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция 5. Пример вычислительного ядра - задача у

C language lect_20_advanced
C language lect_20_advancedC language lect_20_advanced
C language lect_20_advancedRoman Brovko
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
 
Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти
Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памятиЕвгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти
Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памятиFProg
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...a15464321646213
 
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)Mikhail Kurnosov
 
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...Ontico
 
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Mikhail Kurnosov
 
Лекция №5 Организация ЭВМ и систем
Лекция №5 Организация ЭВМ и системЛекция №5 Организация ЭВМ и систем
Лекция №5 Организация ЭВМ и системpianist2317
 
Пути увеличения эффективности реализации алгоритмов машинного обучения
Пути увеличения эффективности реализации алгоритмов машинного обученияПути увеличения эффективности реализации алгоритмов машинного обучения
Пути увеличения эффективности реализации алгоритмов машинного обученияAndrew Babiy
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...a15464321646213
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2Technopark
 
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)Ontico
 
Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008Ontico
 
Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008Ontico
 
Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)Ontico
 
Современная операционная система: что надо знать разработчику / Александр Кри...
Современная операционная система: что надо знать разработчику / Александр Кри...Современная операционная система: что надо знать разработчику / Александр Кри...
Современная операционная система: что надо знать разработчику / Александр Кри...Ontico
 
Исследование работы Кэш-памяти центрального процессора
Исследование работы Кэш-памяти центрального процессораИсследование работы Кэш-памяти центрального процессора
Исследование работы Кэш-памяти центрального процессораSemen Martynov
 
Аппаратная реализация персонального компьютера
Аппаратная реализация персонального компьютераАппаратная реализация персонального компьютера
Аппаратная реализация персонального компьютераstudent_SSGA
 

Similar to Архитектура и программирование потоковых многоядерных процессоров для научных рассчетов. Лекция 5. Пример вычислительного ядра - задача у (20)

C language lect_20_advanced
C language lect_20_advancedC language lect_20_advanced
C language lect_20_advanced
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
 
Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти
Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памятиЕвгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти
Евгений Лазин. Неизменяемая структура данных HAMT для создания БД в памяти
 
Purely practical data structures
Purely practical data structuresPurely practical data structures
Purely practical data structures
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...
 
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
Лекция 4: Оптимизация доступа к памяти (Memory access optimization, caches)
 
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
 
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
 
Лекция №5 Организация ЭВМ и систем
Лекция №5 Организация ЭВМ и системЛекция №5 Организация ЭВМ и систем
Лекция №5 Организация ЭВМ и систем
 
Лекция №5 Организация ЭВМ и систем
Лекция №5 Организация ЭВМ и системЛекция №5 Организация ЭВМ и систем
Лекция №5 Организация ЭВМ и систем
 
Пути увеличения эффективности реализации алгоритмов машинного обучения
Пути увеличения эффективности реализации алгоритмов машинного обученияПути увеличения эффективности реализации алгоритмов машинного обучения
Пути увеличения эффективности реализации алгоритмов машинного обучения
 
Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...Архитектура и программирование потоковых многоядерных процессоров для научных...
Архитектура и программирование потоковых многоядерных процессоров для научных...
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2
 
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
 
Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008
 
Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008
 
Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)Что такое Postgresql (Максим Богук)
Что такое Postgresql (Максим Богук)
 
Современная операционная система: что надо знать разработчику / Александр Кри...
Современная операционная система: что надо знать разработчику / Александр Кри...Современная операционная система: что надо знать разработчику / Александр Кри...
Современная операционная система: что надо знать разработчику / Александр Кри...
 
Исследование работы Кэш-памяти центрального процессора
Исследование работы Кэш-памяти центрального процессораИсследование работы Кэш-памяти центрального процессора
Исследование работы Кэш-памяти центрального процессора
 
Аппаратная реализация персонального компьютера
Аппаратная реализация персонального компьютераАппаратная реализация персонального компьютера
Аппаратная реализация персонального компьютера
 

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

  • 1. Архитектура и программирование потоковых многоядерных процессоров для научных расчётов Лекция 5. Пример вычислительного ядра – задача умножения матриц Текстуры матриц. Текстуры. Атомарные функции. Библиотека CUTIL
  • 2. Процедура разработки программы Общий подход к програмированию Разбить задачу на элементарные блоки данных, над которыми выполняется стандартный алгоритм обработки (единый для всех б блоков) ) Разбить за-/вы- гружаемые данные на элементарные непересекающиеся блоки которые каждый из процессов блоки, прочтёт/запишет Определить конфигурацию грида/блока позволяющее грида/блока, Оптимальное размещение промежуточных данных в регистрах и общей памяти Оптимальную вычислительную загрузку потоковых процессоров Определить график когерентного обращения к памяти процессами при загрузке данных
  • 3. Вычислительная конфигурация GPU Host Device Grid 1 Kernel 1 Block (0, 0) Block (1, 0) Block (2, 0) Block (0, (0 1) Block (1, (1 1) Block (2, (2 1) Grid 2 Kernel 2 Block (1, 1) Thread Thread Thread Thread Thread (0, 0) (1, 0) (2, 0) (3, 0) (4, 0) Thread Thread Thread Thread Thread ( ) (0, 1) ( ) (1, 1) ( ) (2, 1) ( ) (3, 1) ( ) (4, 1) Thread Thread Thread Thread Thread (0, 2) (1, 2) (2, 2) (3, 2) (4, 2) Процессы объединяются в блоки (blocks), внутри которых они имеют общую р щу память (shared memory) и синхронное исполнение Блоки объединяются в сетки (grids) Нет возможности предсказать очерёдность запуска блоков в сетки Между блоками нет и не может быть (см. выше) общей памяти
  • 4. Пример программы для GPU умножение матриц -1 bx 0 1 2 tx BLOCK_W WIDTH BLOCK_W WIDTH Hb Ha M N BLOCK_S SIZE Разбить задачу на элементарные блоки данных, над которыми выполняется стандартный алгоритм обработки (единый для всех блоков) Каждый блок вычисляет некоторую небольшую область результата у р у Каждый тред в блоке вычисляет один элемент этой области bsize-1 012 P 0 by 0 1 2 1 ty Psub bsize-1 BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH Wa Wb 2
  • 5. Пример программы для GPU умножение матриц -2 bx 0 1 2 tx BLOCK_W WIDTH BLOCK_W WIDTH Hb Ha M N BLOCK_S SIZE Разбить данные на элементарные блоки (непересекающиеся), которые каждый из процессов прочтёт/запишет Необходимые области исходных матриц разбиваются на квадратные области Каждый из тредов читает один элемент из этих областей в разделяемую память bsize-1 012 P 0 by 0 1 2 1 ty Psub bsize-1 BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH Wa Wb 2
  • 6. Пример программы для GPU умножение матриц -3 bx 0 1 2 tx Hb Ha M BLOCK_W WIDTH BLOCK_W WIDTH Блок = 16x16= 256 тредов больше чем 192, меньше чем 512 N BLOCK_S SIZE Определить конфигурацию грида/блока, позволяющее Оптимальное размещение промежуточных данных в регистрах и общей памяти Оптимальную вычислительную загрузку потоковых процессоров bsize-1 012 P 0 Целое количество варпов в блоке 0 1 2 by 1 Размеры грида определяются размерами исходных матриц ty Psub bsize-1 BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH Wa Wb 2
  • 7. Пример программы для GPU умножение матриц -4 bx 0 1 2 tx Hb Ha M BLOCK_W WIDTH BLOCK_W WIDTH Регистровая память расходуется незначительно N BLOCK_S SIZE Размер разделяемой памяти = 16KB на мультипроцессор (максимальное количество памяти для б блока) ) В разделяемую память мультипроцессора поместятся данные от 8 блоков bsize-1 012 P 0 Для определения количества регистров, by приходящееся на один 1 тред нужно смотреть PTX код 0 1 2 ty Psub bsize-1 BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH BLOCK_WIDTH BLOCK WIDTH Wa Wb 2
  • 8. Хост функция Хост-функция умножения матриц #define BLOCK SIZE 16 BLOCK_SIZE __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; // Load A and B t the device L d d to th d i float* 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); }
  • 9. GPU ядро умножения матриц __global__ void Muld(float* A, float* B, int wA, int wB, float* C) { global A B wA wB int bx = blockIdx.x; // Block index int by = blockIdx.y; int tx i t t = threadIdx.x; // Thread index th dId Th di d int ty = threadIdx.y; int aBegin = wA * BLOCK_SIZE * by; // Index of the first sub-matrix of A processed by the block int aEnd = aBegin + wA - 1; // Index of the last sub-matrix of A processed by the block int 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 block int bStep = BLOCK_SIZE * wB; // Step size used to iterate through the sub-matrices of B float 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];
  • 10. 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 loaded y () 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 // 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; }
  • 11. Уровень производительности Для матрицы 1024*1024 Автоматическое распределение : 3.0 сек - 45 GFLOPS 1 блок на SM : 3.6 сек. - 35 GFLOPS 2 блока на SM : 3.0 сек. - 45 GFLOPS Очевидно, Очевидно ограничивающим фактором является требование запуска 2 блоков на SM, а не ограничение по разделяемой памяти (8 блоков на SM) Развёртывание циклов помогает (развёрнуто 16 раз) Развернутая программа (автомат) : 1.6 сек. - 80 GFLOPS 1 блок на SM : 2.1 сек. - 61 GFLOPS 2 блока на SM : 1.6 сек. - 80 GFLOPS
  • 12. Уровень производительности (продолжение) Возможный альтернативный график вычислений Loop { Load to Shared Memory y Syncthread() Load to Shared Memory Syncthread() Loop { Compute current subblock Compute current subblock C bbl k Load to Shard Memory Syncthreads() } Syncthreads() }
  • 13. Texture Processor Cluster (TPC) TPC SM 0 Instruction Fetch T Instruction L e 1 Cache Instruction Decode x T t e u x I Shared Memory SP 0 R SP 1 R R SP 5 SP 2 R R SP 6 R R SP 7 F r t e u U L S D F Constant L r & SP 4 SP 3 S R e U L 1 Cache 2 SM 1 1 C Instruction Fetch Instruction L U 1 Cache a Instruction Decode I t ti D d C n a i c t h e c Shared Memory SP 0 S R R SP 1 R R SP 5 h SP 4 F U TEX – Т Текстурный блок – логика йб адресации текстурных массивов в 1D, 2D, 3D + L1 Кэш Текстур S F SP 2 R R SP 6 SP 3 R R SP 7 Constant L 1 Cache Load/Store U e L2 Кэш инструкций и данных для обоих SM x2 Потоковых Мультипроцессора (St ea (Streaming Multiprocessor) g u t p ocesso ) x8 потоковых процессоров (streaming processors) = 8 MAD/clock cycle Регистры для хранения промежуточных р р р у результатов у выполняемых тредов => больше тредов лучше скрыты операции чтения, но межет не хватить регистров
  • 14. Использование текстур (обзор) Текстуры - удобный способ обращения с табличными исходными данными Кэшированы – для каждых 2 SM – общий L1 кэш, общий L2 К 2-х б й б й кэш для всего кристалла Замена разделяемой памяти для RO операндов Нет ё Н жёстких требований к правильности адресации б й Адреса – числа с плавающей точкой (возможно с нормализацией) Позволяют выделять объекты с адресом, находящимся между табличными значениями Аппоксимация ближайшим Линейная и билинейная аппроксимация ( Л й б й (исходя из значений й соседей) Варианты “tile” и “center” Поведение текстуры при выходе адреса за пределы сетки
  • 15. Использование текстур (детали) Объявление вне тела функции - texture<Type, Dim, ReadMode> texRef; Type = тип Dim = 1 | 2 ReadMode = cudaReadModeNormalizedFloat | CudaReadModeElementType Определение – привязывание объявленной ссылки на 1D (линейный массив) или 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);
  • 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 coordinates unsigned 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 -= v -= float float 0.5f; // transform coordinates 0.5f; tu = u*cosf(theta) - v*sinf(theta) + 0.5f; tv = v*cosf(theta) + u*sinf(theta) + 0.5f; // read from texture and write to global memory g_odata[y*width + x] = tex2D(tex, tu, tv); }
  • 17. Использование текстур (пример часть 2) // set texture parameters tex.addressMode[0] = cudaAddressModeWrap; tex.addressMode[1] = cudaAddressModeWrap; p tex.filterMode = cudaFilterModeLinear; tex.normalized = true; // access with normalized texture coordinates // Bind the array to the texture y CUDA_SAFE_CALL( cudaBindTextureToArray( tex, cu_array, channelDesc)); dim3 dimBlock(8, 8, 1); dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, 1); // warmup transformKernel<<< dimGrid, dimBlock, 0 >>>( d_data, width, height, angle); CUDA_SAFE_CALL( cudaThreadSynchronize() ); // execute the kernel transformKernel<<< dimGrid dimBlock 0 >>>( d data width, height, angle); dimGrid, dimBlock, d_data, width height
  • 18. Обращение с памятью из ворпа НЕАТОМАРНЫЕ ИНСТРУКЦИИ (G80) ЕСЛИ какая-либо инструкция исполняемая ворпом пишет в одно место в глобальной или общей памяти ТО количество записей и их очерёдность недетерминированы ОДНАКО по крайней мере одна запись состоится АТОМАРНЫЕ ИНСТРУКЦИИ (G92+) ЕСЛИ какая-либо инструкция исполняемая ворпом пишет/читает/модифицирует одно место в глобальной памяти ТО их очерёдность записей недетерминирована ОДНАКО все записи состоятся последовательно
  • 19. Атомарные функции Функции чтения/модификации/записи данных в глобальную память – основа построения алгоритмов стекового декодирования Работают только с целыми значениями (!) Гарантируют неизменность операнда в процессе операции Арифметические функции: atomicAdd,atomicSub, atomicExch, atomicMax, 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);
  • 20. Библиотека cutil Набор утилит для различных служебных целей (cut* - функции) Макросы типа CUDA_SAFE_CALL - различные ситуции, с синхронизацией, синхронизацией без неё для эмуляции неё, Утилиты профайлинга измерение длительности исполнения CUT_SAFE_CALL( CUT SAFE CALL( cutCreateTimer( &timer)); CUT_SAFE_CALL( cutStartTimer( timer)); CUT_SAFE_CALL( cutStopTimer( timer)); CUT_SAFE_CALL( CUT SAFE CALL( cutDeleteTimer(&timer)); Определение конфликтных ситуаций операций чтения И т.д. => см cutil.h Находится в директории common в составе SDK В отличии от других библиотек предоставляется в виде исходных текстов Необходимо скомпилировать до работы над своим проектом
  • 21. Итоги лекции В результате лекции студенты должны : Получить практический пример составления вычислительного ядра для типовой задачи. Получить представление о свойствах текстур и возможности их применения в научных вычислениях Получить представление о свойствах и возможности применения в научных вычислениях атомарных функций Достаточные знания для начала самостоятельной работы