Parallel Computing in CUDA Michael Garland NVIDIA Research.

Slides:



Advertisements
Similar presentations
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE408/CS483, University of Illinois, Urbana-Champaign 1 ECE408 / CS483 Applied Parallel Programming.
Advertisements

GPU programming: CUDA Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including materials.
Intermediate GPGPU Programming in CUDA
List Ranking and Parallel Prefix
Complete Unified Device Architecture A Highly Scalable Parallel Programming Framework Submitted in partial fulfillment of the requirements for the Maryland.
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
GPU Programming and CUDA Sathish Vadhiyar Parallel Programming.
Introduction to CUDA Programming Histograms and Sparse Array Multiplication Andreas Moshovos Winter 2009 Based on documents from: NVIDIA & Appendix A of.
An Introduction to CUDA and Manycore Graphics Processors Bryan Catanzaro, UC Berkeley Universal Parallel Computing Research Center University of California,
© NVIDIA Corporation 2009 Mark Harris NVIDIA Corporation Tesla GPU Computing A Revolution in High Performance Computing.
NVIDIA Research Parallel Computing on Manycore GPUs Vinod Grover.
Programming with CUDA, WS09 Waqar Saleem, Jens Müller Programming with CUDA and Parallel Algorithms Waqar Saleem Jens Müller.
CUDA and the Memory Model (Part II). Code executed on GPU.
CUDA Grids, Blocks, and Threads
CUDA C/C++ BASICS NVIDIA Corporation © NVIDIA 2013.
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.
GPU Programming EPCC The University of Edinburgh.
An Introduction to Programming with CUDA Paul Richmond
GPU Parallel Computing Zehuan Wang HPC Developer Technology Engineer
Nvidia CUDA Programming Basics Xiaoming Li Department of Electrical and Computer Engineering University of Delaware.
GPU Programming and CUDA Sathish Vadhiyar High Performance Computing.
Programming Massively Parallel Processors Using CUDA & C++AMP Lecture 1 - Introduction Wen-mei Hwu, Izzat El Hajj CEA-EDF-Inria Summer School 2013.
More CUDA Examples. Different Levels of parallelism Thread parallelism – each thread is an independent thread of execution Data parallelism – across threads.
Basic CUDA Programming Computer Architecture 2014 (Prof. Chih-Wei Liu) Final Project – CUDA Tutorial TA Cheng-Yen Yang
1 100M CUDA GPUs Oil & GasFinanceMedicalBiophysicsNumericsAudioVideoImaging Heterogeneous Computing CPUCPU GPUGPU Joy NVIDIA.
Introduction to CUDA Programming Histograms and Sparse Array Multiplication Andreas Moshovos Winter 2009 Based on documents from: NVIDIA & Appendix A of.
Basic C programming for the CUDA architecture. © NVIDIA Corporation 2009 Outline of CUDA Basics Basic Kernels and Execution on GPU Basic Memory Management.
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) {
Basic CUDA Programming Computer Architecture 2015 (Prof. Chih-Wei Liu) Final Project – CUDA Tutorial TA Cheng-Yen Yang
Sparse Matrix-Vector Multiplication on Throughput-Oriented Processors
CUDA All material not from online sources/textbook copyright © Travis Desell, 2012.
+ 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
CUDA programming (continue) Acknowledgement: the lecture materials are based on the materials in NVIDIA teaching center CUDA course materials, including.
Automatic translation from CUDA to C++ Luca Atzori, Vincenzo Innocente, Felice Pantaleo, Danilo Piparo 31 August, 2015.
GPU Architecture and Programming
CUDA - 2.
GPU Programming and CUDA Sathish Vadhiyar Parallel Programming.
Training Program on GPU Programming with CUDA 31 st July, 7 th Aug, 14 th Aug 2011 CUDA Teaching UoM.
CS 193G Lecture 2: GPU History & CUDA Programming Basics.
Introduction to CUDA (1 of n*) Patrick Cozzi University of Pennsylvania CIS Spring 2011 * Where n is 2 or 3.
CS 193G Lecture 5: Parallel Patterns I. Getting out of the trenches So far, we’ve concerned ourselves with low-level details of kernel programming Mapping.
© David Kirk/NVIDIA and Wen-mei W. Hwu, ECE408/CS483, University of Illinois, Urbana-Champaign 1 Introduction to CUDA C (Part 2)
© 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.
Parallel Programming Basics  Things we need to consider:  Control  Synchronization  Communication  Parallel programming languages offer different.
Introduction to CUDA CAP 4730 Spring 2012 Tushar Athawale.
1 GPU programming Dr. Bernhard Kainz. 2 Dr Bernhard Kainz Overview About myself Motivation GPU hardware and system architecture GPU programming languages.
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.
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 Programming and CUDA Sathish Vadhiyar High Performance Computing.
CUDA C/C++ Basics Part 3 – Shared memory and synchronization
Computer Engg, IIT(BHU)
Basic CUDA Programming
CUDA Parallelism Model
Antonio R. Miele Marco D. Santambrogio Politecnico di Milano
Parallel programming with GPGPU coprocessors
Antonio R. Miele Marco D. Santambrogio Politecnico di Milano
ECE 8823A GPU Architectures Module 2: Introduction to CUDA C
6- General Purpose GPU Programming
Parallel Computing 18: CUDA - I
Presentation transcript:

Parallel Computing in CUDA Michael Garland NVIDIA Research

© NVIDIA Corporation 2008 Some Design Goals Scale to 100’s of cores, 1000’s of parallel threads Let programmers focus on parallel algorithms not mechanics of a parallel programming language. Enable heterogeneous systems (i.e., CPU+GPU) CPU & GPU are separate devices with separate DRAMs

© NVIDIA Corporation 2008 Key Parallel Abstractions in CUDA Hierarchy of concurrent threads Lightweight synchronization primitives Shared memory model for cooperating threads

© NVIDIA Corporation 2008 Hierarchy of concurrent threads Parallel kernels composed of many threads all threads execute the same sequential program Threads are grouped into thread blocks threads in the same block can cooperate Threads/blocks have unique IDs Thread t t0 t1 … tB Block b

© NVIDIA Corporation 2008 Example: Vector Addition Kernel // Compute vector sum C = A+B // Each thread performs one pair-wise addition __global__ void vecAdd(float* A, float* B, float* C) { int i = threadIdx.x + blockDim.x * blockIdx.x; C[i] = A[i] + B[i]; } int main() { // Run N/256 blocks of 256 threads each vecAdd >>(d_A, d_B, d_C); } Device Code

© NVIDIA Corporation 2008 Example: Vector Addition Kernel // Compute vector sum C = A+B // Each thread performs one pair-wise addition __global__ void vecAdd(float* A, float* B, float* C) { int i = threadIdx.x + blockDim.x * blockIdx.x; C[i] = A[i] + B[i]; } int main() { // Run N/256 blocks of 256 threads each vecAdd >>(d_A, d_B, d_C); } Host Code

© NVIDIA Corporation 2008 Synchronization of blocks Threads within block may synchronize with barriers … Step 1 … __syncthreads(); … Step 2 … Blocks coordinate via atomic memory operations e.g., increment shared queue pointer with atomicInc() Implicit barrier between dependent kernels vec_minus >>(a, b, c); vec_dot >>(c, c);

© NVIDIA Corporation 2008 What is a thread? Independent thread of execution has its own PC, variables (registers), processor state, etc. no implication about how threads are scheduled CUDA threads might be physical threads as on NVIDIA GPUs CUDA threads might be virtual threads might pick 1 block = 1 physical thread on multicore CPU

© NVIDIA Corporation 2008 What is a thread block? Thread block = virtualized multiprocessor freely choose processors to fit data freely customize for each kernel launch Thread block = a (data) parallel task all blocks in kernel have the same entry point but may execute any code they want Thread blocks of kernel must be independent tasks program valid for any interleaving of block executions

© NVIDIA Corporation 2008 Blocks must be independent Any possible interleaving of blocks should be valid presumed to run to completion without pre-emption can run in any order can run concurrently OR sequentially Blocks may coordinate but not synchronize shared queue pointer: OK shared lock: BAD … can easily deadlock Independence requirement gives scalability

© NVIDIA Corporation 2008 Levels of parallelism Thread parallelism each thread is an independent thread of execution Data parallelism across threads in a block across blocks in a kernel Task parallelism different blocks are independent independent kernels

© NVIDIA Corporation 2008 Memory model Thread Per-thread Local Memory Block Per-block Shared Memory

© NVIDIA Corporation 2008 Memory model Kernel 0... Per-device Global Memory... Kernel 1 Sequential Kernels

© NVIDIA Corporation 2008 Memory model Device 0 memory Device 1 memory Host memory cudaMemcpy()

© NVIDIA Corporation 2008 Using per-block shared memory Variables shared across block __shared__ int *begin, *end; Scratchpad memory __shared__ int scratch[blocksize]; scratch[threadIdx.x] = begin[threadIdx.x]; // … compute on scratch values … begin[threadIdx.x] = scratch[threadIdx.x]; Communicating values between threads scratch[threadIdx.x] = begin[threadIdx.x]; __syncthreads(); int left = scratch[threadIdx.x - 1]; Block Shared

© NVIDIA Corporation 2008 CUDA: Minimal extensions to C/C++ Declaration specifiers to indicate where things live __global__ void KernelFunc(...); // kernel callable from host __device__ void DeviceFunc(...); // function callable on device __device__ int GlobalVar; // variable in device memory __shared__ int SharedVar; // in per-block shared memory Extend function invocation syntax for parallel kernel launch KernelFunc >>(...); // 500 blocks, 128 threads each Special variables for thread identification in kernels dim3 threadIdx; dim3 blockIdx; dim3 blockDim; Intrinsics that expose specific operations in kernel code __syncthreads(); // barrier synchronization

© NVIDIA Corporation 2008 CUDA: Features available on GPU Standard mathematical functions sinf, powf, atanf, ceil, min, sqrtf, etc. Atomic memory operations atomicAdd, atomicMin, atomicAnd, atomicCAS, etc. Texture accesses in kernels texture my_texture; // declare texture reference float4 texel = texfetch(my_texture, u, v);

© NVIDIA Corporation 2008 CUDA: Runtime support Explicit memory allocation returns pointers to GPU memory cudaMalloc(), cudaFree() Explicit memory copy for host ↔ device, device ↔ device cudaMemcpy(), cudaMemcpy2D(),... Texture management cudaBindTexture(), cudaBindTextureToArray(),... OpenGL & DirectX interoperability cudaGLMapBufferObject(), cudaD3D9MapVertexBuffer(), …

© NVIDIA Corporation 2008 Example: Vector Addition Kernel // Compute vector sum C = A+B // Each thread performs one pair-wise addition __global__ void vecAdd(float* A, float* B, float* C) { int i = threadIdx.x + blockDim.x * blockIdx.x; C[i] = A[i] + B[i]; } int main() { // Run N/256 blocks of 256 threads each vecAdd >>(d_A, d_B, d_C); }

© NVIDIA Corporation 2008 Example: Host code for vecAdd // allocate and initialize host (CPU) memory float *h_A = …, *h_B = …; // allocate device (GPU) memory float *d_A, *d_B, *d_C; cudaMalloc( (void**) &d_A, N * sizeof(float)); cudaMalloc( (void**) &d_B, N * sizeof(float)); cudaMalloc( (void**) &d_C, N * sizeof(float)); // copy host memory to device cudaMemcpy( d_A, h_A, N * sizeof(float), cudaMemcpyHostToDevice) ); cudaMemcpy( d_B, h_B, N * sizeof(float), cudaMemcpyHostToDevice) ); // execute the kernel on N/256 blocks of 256 threads each vecAdd >>(d_A, d_B, d_C);

© NVIDIA Corporation 2008 Example: Parallel Reduction Summing up a sequence with 1 thread: int sum = 0; for(int i=0; i<N; ++i) sum += x[i]; Parallel reduction builds a summation tree each thread holds 1 element stepwise partial sums N threads need log N steps one possible approach: Butterfly pattern

© NVIDIA Corporation 2008 Example: Parallel Reduction Summing up a sequence with 1 thread: int sum = 0; for(int i=0; i<N; ++i) sum += x[i]; Parallel reduction builds a summation tree each thread holds 1 element stepwise partial sums N threads need log N steps one possible approach: Butterfly pattern

© NVIDIA Corporation 2008 Parallel Reduction for 1 Block // INPUT: Thread i holds value x_i int i = threadIdx.x; __shared__ int sum[blocksize]; // One thread per element sum[i] = x_i; __syncthreads(); for(int bit=blocksize/2; bit>0; bit/=2) { int t=sum[i]+sum[i^bit]; __syncthreads(); sum[i]=t; __syncthreads(); } // OUTPUT: Every thread now holds sum in sum[i]

© NVIDIA Corporation 2008 Parallel Reduction Across Blocks Code lets B-thread block reduce B-element array For larger sequences: reduce each B-element subsequence with 1 block write N/B partial sums to temporary array repeat until done P.S. this works for min, max, *, and friends too as written requires associative & commutative function can restructure to work with any associative function

© NVIDIA Corporation 2008 Example: Serial S AXPY routine Serial program: compute y = α x + y with a loop void saxpy_serial(int n, float a, float *x, float *y) { for(int i = 0; i<n; ++i) y[i] = a*x[i] + y[i]; } Serial execution: call a function saxpy_serial(n, 2.0, x, y);

© NVIDIA Corporation 2008 Example: Parallel S AXPY routine Parallel execution: launch a kernel uint size = 256; // threads per block uint blocks = (n + size-1) / size; // blocks needed saxpy_parallel >>(n, 2.0, x, y); Parallel program: compute with 1 thread per element __global__ void saxpy_parallel(int n, float a, float *x, float *y) { int i = blockIdx.x*blockDim.x + threadIdx.x; if( i<n ) y[i] = a*x[i] + y[i]; }

© NVIDIA Corporation 2008 Compiling CUDA for GPUs NVCC C/C++ CUDA Application PTX to Target Translator GPU … Target device code PTX Code Generic Specialized CPU Code

© NVIDIA Corporation 2008 SAXPY in PTX 1.0 ISA cvt.u32.u16 $blockid, %ctaid.x; // Calculate i from thread/block IDs cvt.u32.u16 $blocksize, %ntid.x; cvt.u32.u16 $tid, %tid.x; mad24.lo.u32$i, $blockid, $blocksize, $tid; ld.param.u32 $n, [N]; // Nothing to do if n ≤ i setp.le.u32 $p1, $n, bra $L_finish; mul.lo.u32 $offset, $i, 4; // Load y[i] ld.param.u32 $yaddr, [Y]; add.u32 $yaddr, $yaddr, $offset; ld.global.f32 $y_i, [$yaddr+0]; ld.param.u32 $xaddr, [X]; // Load x[i] add.u32 $xaddr, $xaddr, $offset; ld.global.f32 $x_i, [$xaddr+0]; ld.param.f32 $alpha, [ALPHA]; // Compute and store alpha*x[i] + y[i] mad.f32 $y_i, $alpha, $x_i, $y_i; st.global.f32 [$yaddr+0], $y_i; $L_finish:exit;

© NVIDIA Corporation 2008 Sparse matrix-vector multiplication Sparse matrices have relatively few non-zero entries Frequently O(n) rather than O(n 2 ) Only store & operate on these non-zero entries Av[7] = { 3, 1, 2, 4, 1, 1, 1 }; Aj[7] = { 0, 2, 1, 2, 3, 0, 3 }; Ap[5] = { 0, 2, 2, 5, 7 }; Non-zero values Column indices Row pointers Row 0Row 2Row 3 Example: Compressed Sparse Row (CSR) Format

© NVIDIA Corporation 2008 Sparse matrix-vector multiplication float multiply_row(uint rowsize, // number of non-zeros in row uint *Aj, // column indices for row float *Av, // non-zero entries for row float *x) // the RHS vector { float sum = 0; for(uint column=0; column<rowsize; ++column) sum += Av[column] * x[Aj[column]]; return sum; } Av[7] = { 3, 1, 2, 4, 1, 1, 1 }; Aj[7] = { 0, 2, 1, 2, 3, 0, 3 }; Ap[5] = { 0, 2, 2, 5, 7 }; Non-zero values Column indices Row pointers Row 0Row 2Row 3

© NVIDIA Corporation 2008 Sparse matrix-vector multiplication float multiply_row(uint size, uint *Aj, float *Av, float *x); void csrmul_serial(uint *Ap, uint *Aj, float *Av, uint num_rows, float *x, float *y) { for(uint row=0; row<num_rows; ++row) { uint row_begin = Ap[row]; uint row_end = Ap[row+1]; y[row] = multiply_row(row_end-row_begin, Aj+row_begin, Av+row_begin, x); }

© NVIDIA Corporation 2008 Sparse matrix-vector multiplication float multiply_row(uint size, uint *Aj, float *Av, float *x); __global__ void csrmul_kernel(uint *Ap, uint *Aj, float *Av, uint num_rows, float *x, float *y) { uint row = blockIdx.x*blockDim.x + threadIdx.x; if( row<num_rows ) { uint row_begin = Ap[row]; uint row_end = Ap[row+1]; y[row] = multiply_row(row_end-row_begin, Aj+row_begin, Av+row_begin, x); }

© NVIDIA Corporation 2008 Adding a simple caching scheme __global__ void csrmul_cached( … … … … … … ) { uint begin = blockIdx.x*blockDim.x, end = begin+blockDim.x; uint row = begin + threadIdx.x; __shared__ float cache[blocksize]; // array to cache rows if( row<num_rows) cache[threadIdx.x] = x[row]; // fetch to cache __syncthreads(); if( row<num_rows ) { uint row_begin = Ap[row], row_end = Ap[row+1]; float sum = 0; for(uint col=row_begin; col<row_end; ++col) { uint j = Aj[col]; // Fetch from cached rows when possible float x_j = (j>=begin && j<end) ? cache[j-begin] : x[j]; sum += Av[col] * x_j; } y[row] = sum; }

© NVIDIA Corporation 2008 Basic Efficiency Rules Develop algorithms with a data parallel mindset Minimize divergence of execution within blocks Maximize locality of global memory accesses Exploit per-block shared memory as scratchpad Expose enough parallelism

© NVIDIA Corporation 2008 Summing Up CUDA = C + a few simple extensions makes it easy to start writing basic parallel programs Three key abstractions: 1.hierarchy of parallel threads 2.corresponding levels of synchronization 3.corresponding memory spaces Supports massive parallelism of manycore GPUs

© NVIDIA Corporation 2008 Questions?