基于CUDA的GPU并行计算 Compute Unified Device Architecture 内容 概述 CUDA的硬件 CUDA的软件 性能提升 并行计算 2015/4/13 南京大学多媒体研究所 2 概述 摩尔定律 2015/4/13 南京大学多媒体研究所 4 摩尔定律的失效 晶体管尺寸 流水线级数 能量墙 存储墙 2015/4/13 南京大学多媒体研究所 5 新摩尔定律 未来计算机硬件不会更快,但会更“宽” No longer get faster, just wider 必须重新设计算法 2015/4/13 南京大学多媒体研究所 6 What is driving the many-cores? 600 Tesla C870 500 GeForce 8800 GTX GFLOPS 400 Quadro FX 5600 300 G71 G70-512 G70 200 100 NV35 NV30 0 Jan 2003 1 NV40 3.0 GHz Core 2 Duo 3.0 GHz Core 2 Quad 3.0 GHz Pentium 4 Jul 2003 Jan 2004 Jul 2004 Jan 2005 Jul 2005 Jan 2006 Jul 2006 Jan 2007 Jul 2007 Based on slide 7 of S. Green, “GPU Physics,” SIGGRAPH 2007 GPGPU Course. http://www.gpgpu.org/s2007/slides/15-GPGPU-physics.pdf GPU与CPU的不同 The GPU is specialized for compute-intensive, massively data parallel computation (exactly what graphics rendering is about) So, more transistors can be devoted to data processing rather than data caching and flow control ALU ALU ALU ALU Control CPU GPU Cache DRAM DRAM The fast-growing video game industry exerts strong economic pressure for constant innovation 什么是GPU计算 GLSL/HLSL 2015/4/13 南京大学多媒体研究所 9 什么是CUDA 编程语言 CUDA可以使用C、Fortan等语言,SL是类C语言 执行方式 CUDA编译成汇编语言,执行时由显卡编译为机器指令;SL则 是在执行时载入、编译,速度较慢。 计算精度 CUDA满足IEEE-754浮点标准,支持单、双精度浮点运算 编程方式 CUDA更加自由;SL则需要模拟渲染过程。 对硬件的适应 2015/4/13 南京大学多媒体研究所 10 为什么GPU比CPU快 更高浮点运算能力 更快的存储访问速度 更多的快速存储单元 更迅速的线程切换速度 2015/4/13 南京大学多媒体研究所 11 更快的存储访问速度 CPU与内存通过总线进行数据交换 GPU与其内存都位于显卡上 2015/4/13 南京大学多媒体研究所 12 CUDA的硬件 G80 CUDA mode – A Device Example Host Input Assembler Thread Execution Manager Parallel Data Cache Parallel Data Cache Parallel Data Cache Parallel Data Cache Parallel Data Cache Parallel Data Cache Parallel Data Cache Parallel Data Cache Texture Texture Texture Texture Texture Texture Texture Texture Texture Load/store Load/store Load/store Load/store Global Memory Load/store Load/store Streaming Multiprocessor (SM) 2015/4/13 南京大学多媒体研究所 15 CUDA执行模型 t0 t1 t2 … tm SM 0 SM 1 MT IU MT IU SP SP Shared Memory Shared Memory Blocks •Up to 8 blocks to each SM as resource allows •SM in G80 can take up to 768 threads t0 t1 t2 … tm Blocks 存储器模型 Register Local shared Global Constant Texture Host memory Pinned host memory 寄存器与local memory 对每个线程来说,寄存器都是线程私有的--这与CPU中 一样。如果寄存器被消耗完,数据将被存储在本地存储 器(local memory)。Local memory对每个线程也是 私有的,但是local memory中的数据是被保存在显存 中,而不是片内的寄存器或者缓存中,速度很慢。线程 的输入和中间输出变量将被保存在寄存器或者本地存储 器中。 Shared memory 用于线程间通信的共享存储器。共享存储器是一块可以 被同一block中的所有thread访问的可读写存储器。 访问共享存储器几乎和访问寄存器一样快,是实现线程 间通信的延迟最小的方法。 共享存储器可以实现许多不同的功能,如用于保存共用 的计数器(例如计算循环次数)或者block的公用结果(例 如计算512个数的平均值,并用于以后的计算)。 constant memory, texture memory 利用GPU用于图形计算的专用单元发展而来的高速只 读缓存 速度与命中率有关,不命中时将进行对显存的访问 常数存储器空间较小(只有64k),支持随机访问。从 host端只写,从device端只读 纹理存储器尺寸则大得多,并且支持二维寻址。(一个 数据的“上下左右”的数据都能被读入缓存)适合实现 图像处理算法和查找表 全局存储器 使用的是普通的显存,无缓存,可读写,速度慢 整个网格中的任意线程都能读写全局存储器的任意位置 ,并且既可以从CPU访问,也可以从CPU访问。 各种存储器的延迟 register: 1 周期 shared memory: 1 周期( 无bank conflict ) - 16 周期( 发生16路 bank conflict) texture memory: 1 ( 命中) - 数百周期(不命中) constant memory: 1 ( 命中) - 数百周期( 不命中) global local memory: 数百周期 各存储器大小 每个SM中有64K(GT200)或者32K(G8x, G9x)寄 存器,寄存器的最小单位是32bit的register file 每个SM中有16K shared memory 一共可以声明64K的constant memory,但每个SM 的cache序列只有8K 可以声明很大的texture memory,但是实际上的 texture cache序列为每SM 6-8K CUDA的软件 当前的GPU开发环境 Cg:优秀的图形学开发环境,但不适合GPU通用计算 开发 ATI stream:硬件上已经有了基础,但只有低层次汇 编能够使用所有资源。高层次抽象Brook本质上是基于 上一代GPU的,缺乏良好的编程模型 OpenCL:联合制定的标准,抽象层次较低,对硬件直 接操作更多,代码需要根据不同硬件优化 CUDA:目前最佳选择 下载CUDA软件 http://www.nvidia.cn/object/cuda_get_cn. html CUDA SDK CUDA Visual Profiler 2015/4/13 南京大学多媒体研究所 26 CUDA程序模板 Main(){ //Allocate memory on GPU float *Md; cudaMalloc((void**)&Md, size); //Copy data from CPU to GPU cudaMemcpy(Md, M, size, cudaMemcpyHostToDevice); //Call GPU kernel function kernel<<<dimGrid, dimBlock>>> (arguments); //Copy data from GPU back to CPU CopyFromDeviceMatrix(M, Md); //Free device matrices FreeDeviceMatrix(Md); } 2015/4/13 南京大学多媒体研究所 27 性能提升 共享内存的使用 2015/4/13 南京大学多媒体研究所 29 优化原则:active block 一个SM中可以有多个block等待处理,在一 个warp需要访问存储器或者同步时,另外 一个warp可以使用执行单元的资源 增加active block对提高SM利用率有好处 增加active block只是手段,不是最终的评 价标准。最终目的是要隐藏延迟 优化原则:active block 每个SM最多可以有768(G8x,G9x)或者 1024(GT200)个active thread 这些active thread最多可以属于8个block 还有受到SM中shared memory和 register的制约 最后的active block数量是由以上四个条件 中的“短板”决定 并行计算 Vector Reduction with Branch Divergence Thread 0 0 1 0+1 2 0...3 3 0..7 Thread 2 1 2 2+3 Thread 4 3 4 4+5 4..7 Thread 6 5 6 6+7 Thread 8 7 8 8+9 8..11 8..15 Thread 10 9 10 10+11 11 A simple implementation Assume we have already loaded array into __shared__ float partialSum[] unsigned int t = threadIdx.x; for (unsigned int stride = 1; stride < blockDim.x; stride *= 2) { __syncthreads(); if (t % (2*stride) == 0) partialSum[t] += partialSum[t+stride]; } No Divergence until < 16 sub-sums Thread 0 0 1 0+16 3 4 1 2 3 … 13 14 15 15+31 16 17 18 19 A better implementation Assume we have already loaded array into __shared__ float partialSum[] unsigned int t = threadIdx.x; for (unsigned int stride = blockDim.x; stride > 1; stride >> 1) { __syncthreads(); if (t < stride) partialSum[t] += partialSum[t+stride]; } Memory Coalescing When accessing global memory, peak performance utilization occurs when all threads in a Warp access continuous memory locations. No coalesced Md coalesced Nd WIDTH Thread 1 Thread 2 WIDTH Memory Access Pattern Md Nd WIDTH Original Access Pattern WIDTH Copy into scratchpad memory Md Tiled Access Pattern Nd Perform multiplication with scratchpad values