CUDA programming (continue) Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including.

Slides:



Advertisements
Similar presentations
GPU programming: CUDA Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including materials.
Advertisements

Intermediate GPGPU Programming in CUDA
CUDA programming (continue) Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including.
1 ITCS 6/8010 CUDA Programming, UNC-Charlotte, B. Wilkinson, Jan 28, 2011 GPUMemories.ppt GPU Memories These notes will introduce: The basic memory hierarchy.
1 ITCS 5/4145 Parallel computing, B. Wilkinson, April 11, CUDAMultiDimBlocks.ppt CUDA Grids, Blocks, and Threads These notes will introduce: One.
GPU programming: CUDA Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including materials.
More on threads, shared memory, synchronization
Programming with CUDA, WS09 Waqar Saleem, Jens Müller Programming with CUDA and Parallel Algorithms Waqar Saleem Jens Müller.
Tutorial on Distributed High Performance Computing 14:30 – 19:00 (2:30 pm – 7:00 pm) Wednesday November 17, 2010 Jornadas Chilenas de Computación 2010.
1 ITCS 6/8010 CUDA Programming, UNC-Charlotte, B. Wilkinson, March 5, 2011, 3-DBlocks.ppt Addressing 2-D grids with 3-D blocks Class Discussion Notes.
CUDA Grids, Blocks, and Threads
Programming with CUDA WS 08/09 Lecture 3 Thu, 30 Oct, 2008.
1 ITCS 4/5010 CUDA Programming, UNC-Charlotte, B. Wilkinson, Jan 28, 2013, 3-DBlocks.ppt Addressing 2-D grids with 3-D blocks Class Discussion Notes.
Shekoofeh Azizi Spring  CUDA is a parallel computing platform and programming model invented by NVIDIA  With CUDA, you can send C, C++ and Fortran.
© David Kirk/NVIDIA and Wen-mei W. Hwu, , SSL 2014, ECE408/CS483, University of Illinois, Urbana-Champaign 1 ECE408 / CS483 Applied Parallel Programming.
An Introduction to Programming with CUDA Paul Richmond
More CUDA Examples. Different Levels of parallelism Thread parallelism – each thread is an independent thread of execution Data parallelism – across threads.
CUDA Programming. Floating Point Operations for the CPU and the GPU.
Introduction to CUDA (1 of 2) Patrick Cozzi University of Pennsylvania CIS Spring 2012.
Introduction to CUDA 1 of 2 Patrick Cozzi University of Pennsylvania CIS Fall 2012.
First CUDA Program. #include "stdio.h" int main() { printf("Hello, world\n"); return 0; } #include __global__ void kernel (void) { } int main (void) {
GPU Programming with CUDA – Optimisation Mike Griffiths
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE498AL, University of Illinois, Urbana-Champaign 1 Programming Massively Parallel Processors CUDA Threads.
© David Kirk/NVIDIA and Wen-mei W. Hwu Urbana, Illinois, August 10-14, VSCSE Summer School 2009 Many-core processors for Science and Engineering.
+ CUDA Antonyus Pyetro do Amaral Ferreira. + The problem The advent of multicore CPUs and manycore GPUs means that mainstream processor chips are now.
CIS 565 Fall 2011 Qing Sun
1 ECE 8823A GPU Architectures Module 3: CUDA Execution Model © David Kirk/NVIDIA and Wen-mei Hwu, ECE408/CS483/ECE498al, University of Illinois,
1 ITCS 4/5010 CUDA Programming, UNC-Charlotte, B. Wilkinson, Jan 22, 2013 MemCoalescing.ppt Memory Coalescing These notes will demonstrate the effects.
Today’s lecture 2-Dimensional indexing Color Format Thread Synchronization within for- loops Shared Memory Tiling Review example programs Using Printf.
CUDA - 2.
Lecture 6: Shared-memory Computing with GPU. Free download NVIDIA CUDA a-downloads CUDA programming on visual studio.
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE498AL, University of Illinois, Urbana-Champaign 1 ECE498AL Lecture 3: A Simple Example, Tools, and.
Training Program on GPU Programming with CUDA 31 st July, 7 th Aug, 14 th Aug 2011 CUDA Teaching UoM.
1 SC12 The International Conference for High Performance Computing, Networking, Storage and Analysis Salt Lake City, Utah. Workshop 119: An Educator's.
Introduction to CUDA (1 of n*) Patrick Cozzi University of Pennsylvania CIS Spring 2011 * Where n is 2 or 3.
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE408/CS483, University of Illinois, Urbana-Champaign 1 ECE408 / CS483 Applied Parallel Programming.
OpenCL Joseph Kider University of Pennsylvania CIS Fall 2011.
CUDA All material not from online sources/textbook copyright © Travis Desell, 2012.
Parallel Programming Basics  Things we need to consider:  Control  Synchronization  Communication  Parallel programming languages offer different.
CUDA Memory Types All material not from online sources/textbook copyright © Travis Desell, 2012.
Introduction to CUDA CAP 4730 Spring 2012 Tushar Athawale.
Lecture 8 : Manycore GPU Programming with CUDA Courtesy : SUNY-Stony Brook Prof. Chowdhury’s course note slides are used in this lecture note.
© David Kirk/NVIDIA and Wen-mei W. Hwu, CS/EE 217 GPU Architecture and Programming Lecture 2: Introduction to CUDA C.
Introduction to CUDA 1 of 2 Patrick Cozzi University of Pennsylvania CIS Fall 2014.
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE408/CS483, University of Illinois, Urbana-Champaign 1 ECE 8823A GPU Architectures Module 2: Introduction.
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE498AL, University of Illinois, Urbana-Champaign 1 CUDA Threads.
1 ITCS 5/4010 Parallel computing, B. Wilkinson, Jan 14, CUDAMultiDimBlocks.ppt CUDA Grids, Blocks, and Threads These notes will introduce: One dimensional.
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE408/CS483, University of Illinois, Urbana-Champaign 1 ECE408 / CS483 Applied Parallel Programming.
GPU Performance Optimisation Alan Gray EPCC The University of Edinburgh.
1 ITCS 4/5145GPU Programming, UNC-Charlotte, B. Wilkinson, Nov 4, 2013 CUDAProgModel.ppt CUDA Programming Model These notes will introduce: Basic GPU programming.
Introduction to CUDA Programming CUDA Programming Introduction Andreas Moshovos Winter 2009 Some slides/material from: UIUC course by Wen-Mei Hwu and David.
Matrix Multiplication in CUDA Kyeo-Reh Park Kyeo-Reh Park Nuclear & Quantum EngineeringNuclear & Quantum Engineering.
1 Workshop 9: General purpose computing using GPUs: Developing a hands-on undergraduate course on CUDA programming SIGCSE The 42 nd ACM Technical.
CUDA C/C++ Basics Part 3 – Shared memory and synchronization
Computer Engg, IIT(BHU)
CUDA Parallelism Model
CUDA Grids, Blocks, and Threads
Antonio R. Miele Marco D. Santambrogio Politecnico di Milano
Memory Coalescing These notes will demonstrate the effects of memory coalescing Use of matrix transpose to improve matrix multiplication performance B.
Memory and Data Locality
ECE 8823A GPU Architectures Module 3: CUDA Execution Model -I
Antonio R. Miele Marco D. Santambrogio Politecnico di Milano
ECE 8823A GPU Architectures Module 2: Introduction to CUDA C
CUDA Grids, Blocks, and Threads
General Purpose Graphics Processing Units (GPGPUs)
GPU Lab1 Discussion A MATRIX-MATRIX MULTIPLICATION EXAMPLE.
Chapter 4:Parallel Programming in CUDA C
Quiz Questions CUDA ITCS 4/5145 Parallel Programming, UNC-Charlotte, B. Wilkinson, 2013, QuizCUDA.ppt Nov 12, 2014.
6- General Purpose GPU Programming
Parallel Computing 18: CUDA - I
Presentation transcript:

CUDA programming (continue) Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including materials from Wisconsin (Negrut), North Carolina Charlotte (Wikinson/Li) and NCSA (Kindratenko).

Topics CUDA C extensions Implementing MM on GPU – Memory hierarchy – synchronization

CUDA C extensions Declaration specifiers to indicate where things live __global__ void mykernel(…) // kernel function on GPU __device__ int globalVar; // variable in device __shared__ int sharedVar; // in per block shared memory Parallel kernel launch Mykernel >> (…); // launch 500 blocks with 128 threads each Special variables – Dim3 threadIdx, blockIdx; // thread/block ID – Dim3 blockDim, gridDim; //thread/block size Intrinsics for specific operations in kernel – __syncthreads(); // barrier synchronization

CUDA thread organization hierarchy of threads – Blocks of threads in 1, 2, or 3 dimensions. – The collection of block is called a grid. Grids can be 1D or 2D. – The maximum number of threads inside each block, and the number of thread blocks in a grid is limited.

Cuda thread organization Threads and blocks have IDs – So each thread can decide what data to work on. Block ID (blockIdx): 1D, 2D – ID within a grid Thread ID (threadIdx): 1D, 2D or 3D: ID within a block.

Device characteristics – hardware limitations NVIDIA defined “compute capabilities” 1.0, 1.1, … with limits and features – Give the limits of threads per block, total number of blocks, etc. Compute capability 1.0 – Max number of threads per block = 512 – Max sizes of x- and y-dimension of thread block = 512 – Maximum size of each dimension of grid of thread blocks = – Currently compute capability 4.0. Can decide program parameters by querying the compute capability.

Specifying Grid/Block structure The programmer need to provide each kernel call with: Number of blocks in each dimension Threads per block in each dimension myKernel >>(arg1, … ); B – a structure that defines the number of blocks in the grid in each dimension (1D or 2D). T – a structure that defines the number of threads in a block in each dimension (1D, 2D, or 3D). B and T are of type dim3 (uint3).

1-D grid and/or 1-D blocks For 1-D structure, one can use an integer for each of B and T in: myKernel >>(arg1, … ); B – An integer would define a 1D grid of that size T –An integer would define a 1D block of that size myKernel >>(arg1, … ); Grids can be 2D and blocks can be 2D or 3D – struct dim3 {x; y; z;} threadIdx, blockIdx; Grid/block size – Dim3 gridDim; size of grid dimension x, y (z not used) – Dim3 blockDim; - size of grid dimension,

Compute global 1-D thread ID dim3 threadIdx.x -- “thread index” within block in “x” dimension blockIdx.x -- “block index” within grid in “x” dimension blockDim.x -- “block dimension” in “x” dimension (i.e. number of threads in a block in the x dimension) Full global thread ID in x dimension can be computed by: x = blockIdx.x * blockDim.x + threadIdx.x; how to fix vecadd.cu to make it work for larger vectors? See vecadd1.cu. What is the right number of threads per block?

Compute global 1-D thread ID threadIdx.x blockIdx.x = 1blockIdx.x = 0blockIdx.x = 2 gridDim = 3 x 1 blockDim = 8 x 1 Global thread ID = blockIdx.x * blockDim.x + threadIdx.x = 2 * = thread 18 with linear global addressing Global ID 18

1D grid/block examples __global__ void vecadd(float* A, float* B, float* C) { int i = threadIdx.x; // threadIdx is a CUDA built-in variable C[i] = A[i] + B[i]; } Vecadd >>( dev_A, dev_B, dev_C ); __global__ void vecadd(float* A, float* B, float* C) { int i = blockIdx.x * blockDim.x + threadIdx.x; C[i] = A[i] + B[i]; } vecadd >>( dev_A, dev_B, dev_C );

Higher dimensional grids/blocks Grids can be 2D and blocks can be 2D or 3D – struct dim3 {x; y; z;}; Grid/block size – Dim3 gridDim size of grid dimension x, y (z not used) – Dim3 blockDim - size of grid dimension,

2D grid/blocks To set dimensions, use for example: dim3 grid(16, 16); // Grid x 16 blocks dim3 block(32, 32); // Block x 32 threads myKernel >>(...); which sets: gridDim.x = 16 gridDim.y = 16 blockDim.x = 32 blockDim.y = 32 blockDim.z = 1

2-D grids and 2-D blocks threadID.x threadID.y blockIdx.y * blockDim.y + threadIdx.y blockIdx.x * blockDim.x + threadIdx.x

Flatten 2 dimension array into linear memory Generally memory allocated dynamically on device (GPU) and we cannot not use two- dimensional indices (e.g. A[row][column]) to access array as we might otherwise. Need to know how array is laid out in memory and then compute distance from the beginning of the array. Row major and column major order storage of multi-dimensional arrays.

Flattening an array Number of columns, N column Array element a[row][column] = a[offset] offset = column + row * N where N is the number of items in a row row * number of columns row 0 0 N-1

2D grid/block example: matrix addition #define N 2048 // size of arrays __global__void addMatrix (int *a, int *b, int *c) { int col = blockIdx.x*blockDim.x+threadIdx.x; int row =blockIdx.y*blockDim.y+threadIdx.y; int index = col + row * N; if ( col < N && row < N) c[index]= a[index] + b[index]; } int main() {... dim3 dimBlock (16,16); dim3 dimGrid (N/dimBlock.x, N/dimBlock.y); addMatrix >>(devA, devB, devC); … }

Impact of the sizes of threads/block See matrixmul.cu. Following is the execution trace: A warp can only contain threads in one block. We need at least 32 threads in one block!! time./a.out 3.318u 3.402s 0: % 0+0k 0+0io 0pf+0w time./a.out u 3.200s 0: % 0+0k 0+0io 0pf+0w time./a.out u 3.129s 0: % 0+0k 0+0io 0pf+0w time./a.out u 3.227s 1: % 0+0k 0+0io 0pf+0w time./a.out u 3.917s 3: % 0+0k 0+0io 0pf+0w

CUDA extension to declare kernel routines __global__indicates routine can only be called from host and only executed on device __device__indicates routine can only be called from device and only executed on device __host__indicates routine can only be called from host and only executed on host

Routine for device __global__ routine must have a void return value. Generally cannot call C library routines except CUDA built-in math routines such as sin, cos, etc. – Check NVIDIA CUDA programming guide for details. CUDA also has device only routines.

Example for 2D grid/blocks Matrix multiply: for (i=0; i<N; i++) for(j=0; j<K; j++) for (k=0; k<M; k++) c[i][j] += a[i][k] * b[k][j] 2D mesh must be stored in the linear (1D) array (column major order) c[i][j] = c[i+N*j] = *(c+i+N*j); a[i][k] = a[i+K*j] = *(a+i+K*k);

First cut Using one thread to compute one c[i][j], a total of N*K threads will be needed. – N*K blocks of threads and 1 thread each block – See mm0.cu // kernel MM routine __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = blockIdx.x, j = blockIdx.y; float sum = 0.0f; for (int k = 0; k< M; k++) sum += a[i+N*k] * b[k+K*j]; c [i+N*j] = sum; } dim3 dimBlock(1); dim3 dimGrid(N, N); mmkernel >> (dev_A, dev_B, dev_C, N, M, K);

Another try – See mm0_1.cu // kernel MM routine __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = threadIdx.x, j = threadIdx.y; float sum = 0.0f; for (int k = 0; k< M; k++) sum += a[i+N*k] * b[k+K*j]; c [i+N*j] = sum; } dim3 dimBlock(1); dim3 dimGrid(N, K); mmkernel >> (dev_A, dev_B, dev_C, N, M, K); Another thing wrong here?

Second try Add threads to blocks to exploit the SIMT (SIMD) support – need to have at least 32 threads per block to have one 32 thread warp. – The more the better (GPU will have more options).

CPU and GPU memory Mm with blocks of threads __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = blockIdx.x * BLOCK_SIZE + threadIdx.x, j = blockIdx.y; float sum = 0.0f; for (int k = 0; k< M; k++) sum += a[i+N*k] * b[k+K*j]; c [i+N*j] = sum; } dim3 dimBlock(BLOCK_SIZE); dim3 dimGrid(N/BLOCK_SIZE, K); mmkernel >> (dev_A, dev_B, dev_C, N, M, K); Notice the relationship between index calculation and kernel invocation. Try mm1.cu with different BLOCK_SIZE’s

CUDA memory hierarchy Register: per-thread basis – Private per thread – Can spill into local memory (perf. hit) Shared Memory: per-block basis – Shared by threads of the same block – Used for: Inter-thread communication Global Memory: per-application basis – Available for use to all threads – Used for: Inter-thread communication – Also used for inter-grid communication Thread Register Grid 0... Global Device Memory... Grid 1 Sequential Grids in Time Block Shared Memory 27

CUDA memory allocation MemoryDeclarationScope Lifetime RegistersAuto variablesThreadKernel other than arrays LocalAuto arrays ThreadKernel Shared__shared__BlockKernel Global__device__GridApplication Constant__constant__GridApplication

An example __global__ float A[1000]; __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = blockIdx.x * BLOCK_SIZE + threadIdx.x; int j = blockIdx.y; int tx = threadIdx.x; __shared__ float cb[BLOCK_SIZE]; int workb[BLOCK_SIZE]; …… } Which type of variables are A, i, j, cb, workb?

MM with shared memory In mm1.cu, threads use register variables and global arrays A block of BLOCK_SIZE threads is used to compute: BLOCK_SIZE c items: c[0][0], c[1][0], c[2][0], …. C[BLOCK_SIZE][0] – The calculation: C[0][0] = A[0][0] * B[0][0] + A[0][1]*B[1][0] + A[0][2] * B[2][0] … C[1][0] = A[1][0] * B[0][0] + A[1][1]*B[1][0] + A[1][2] * B[2][0] … C[2][0] = A[2][0] * B[0][0] + A[2][1]*B[1][0] + A[2][2] * B[2][0] … – A matrix has different values in different threads – can’t use shared memory – B matrix has the same items Put B in shared memory may reduce the (global) memory traffic. Shared memory in GPU is limited, can’t hold the whole column: need to reduce the memory footprint. How? – for(k=0; i<M; k++) C[i][j] += A[i][k]*B[k][j]

MM with shared memory for(k=0; i<M; k++) C[i][j] += A[i][k]*B[k][j] For (ks=0; ks < M; ks+=TSIZE) for(k=ks; k<ks+TSIZE; k++) C[i][j] += A[i][k] * B[k][j]; For(ks=0; ks<M; ks+=TSIZE) Forall (k=ks; k<ks+TSIZE; k++) workB[k][j] = B[k][j]; for (k=ks; k<ks+TSIZE;k++) C[i][j] += A[i][k] * workB[k][j];

MM with shared memory __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = blockIdx.x * BLOCK_SIZE + threadIdx.x; int j = blockIdx.y; int tx = threadIdx.x; __shared__ float cb[BLOCK_SIZE]; float sum = 0.0f; for (int ks = 0; ks < M; ks+= BLOCK_SIZE) { cb[tx] = b[ks+tx+M*j]; // copy from global to shared, all threads parallel read for (int k = ks; k< ks+BLOCKINGSIZE; k++) sum += a[i+N*k] * cb[k-ks]; } c [i+N*j] = sum; } Any problem here?

MM with shared memory __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = blockIdx.x * BLOCK_SIZE + threadIdx.x; int j = blockIdx.y; int tx = threadIdx.x; __shared__ float cb[BLOCK_SIZE]; float sum = 0.0f; for (int ks = 0; ks < M; ks+= BLOCK_SIZE) { cb[tx] = b[ks+tx+M*j]; // all BLOCK_SIZE threads parallel read for (int k = ks; k< ks+BLOCKINGSIZE; k++) sum += a[i+N*k] * cb[k-ks]; } c [i+N*j] = sum; } True dependence due to shared memory Anti-dependence

MM with shared memory __global__ void mmkernel(float *a, float *b, float *c, int N, int M, int K) { int i = blockIdx.x * BLOCK_SIZE + threadIdx.x; int j = blockIdx.y; int tx = threadIdx.x; __shared__ float cb[BLOCK_SIZE]; float sum = 0.0f; for (int ks = 0; ks < M; ks+= BLOCK_SIZE) { cb[tx] = b[ks+tx+M*j]; // all BLOCK_SIZE threads parallel read __syncthreads(); // barrier among all threads in a block for (int k = ks; k< ks+BLOCKINGSIZE; k++) sum += a[i+N*k] * cb[k-ks]; __syncthreads(); // barrier among all threads in a block } c [i+N*j] = sum; } See mm2.cu

More schemes to improve MM performance Compute multiple points in each threads – See mm3.cu Using 2D block and 2D grid.

More information about __syncthreads() All threads must reach the barrier before any thread can move on. – Threads arrives early must wait __syncthreads() is kernel only.

More information about __syncthreads() Only synchronize within a block. Barriers in different blocks are independent. Barrier Block 0 Continue Barrier Block n-1 Continue Separate barriers

More information about __syncthreads() CUDA requires threads to synchronize using the exact the same __syncthreads() calls. Cannot do if... __syncthreads() else … __syncthreads() What if we want synchronize among all threads? – Make separate kernel invocations.