读书笔记来自这里
APOD
APOD
表示Assess,Parallelize, Optimize, Deploy。是Nvidia官方提出的CUDA应用程序的周期性设计模式,目的很明确,让开发者快速找到程序中可以并行的部分,尽可能地加速计算。Assess 作为循环设计的入口,评估程序中最耗时的代码部分。
Parallelize 根据原始代码,调用现有的GPU优化库(如
cuBLAS
,cuFFT
或Thrust
),也可以简单地添加一些预处理器指令作为并行化编译器的提示。Optimize 有很多方法,可以从很多角度,比如 overlapping data transfers, fine-tuning floating-point operation sequences 等等。这一步一定要用可用的优化工具。
Deploy 经过初步优化后,保证正确性,在有限时间内得到一个较好的结果。而不是将所有可能优化都实现。
根据具体任务和产品,迭代4步骤。尽可能的得到好的性能提升。
建立优化优先级
在执行优化前要建立优化优先级。
高优化优先级是一些优化,这些优化对于大部分CUDA程序而言可以显著提升性能。低优化优先级是一些小的优化,这些优化可能只适用于某些特定的情况下。
先处理高优先级的优化,后解决低优先级的优化。这保证了在有限时间内提供足有的结果,并且避免了过早优化(premature optimization)。
常见高优先级:
- 用profiler工具找到最耗时的部分
- 并行处理可以并行的串行部分
Host 和 Device 的不同
同时含有CPU和GPU的计算系统称作是异构计算系统(Heterogeneous Computing)。为了有效是哟个CUDA,有必要知道Host和Device 的不同。
线程资源
Host上的流水线可以支持有限数量的并发线程。比如,具有2个32核芯处理器的服务器只能同时运行64个线程(如果CPU支持同时多线程,那么可同时运行的线程数为64的倍数,如128,192)。
相比之下,CUDA设备上最基本的并行执行单元包含32个线程(一个warp)。现代NVIDIA GPU可以在多处理器上同时支持最多2048个活动线程。如果一个GPU上有80个多处理器(SM),这表示可以有超过160000个并发活动线程。
线程本身
CPU上的线程通常是重量级实体。操作系统必须用其他线程交换CPU执行通道上的线程,以提供多线程功能。因此,上下文切换(当两个线程被交换时)是缓慢而昂贵的。
相比之下,GPU上的线程是轻量级。在一个典型的系统中,数千个线程排队等待工作。如果GPU要等待一个warp,它只需在另一个warp上开始执行工作。因为单独的寄存器被分配给所有活动线程,所以在GPU线程之间切换时不需要交换寄存器或其他状态。资源一直分配给每个线程,直到它完成执行。
简而言之,CPU内核目的是最小化每次一小部分线程的等待时间,而GPU则被设计成处理大量并发、轻量级线程以最大化吞吐量。
RAM
Host由CPU和系统内存构成,Device由GPU和显卡上的存储器构成。所以说,Host和Device有各自的RAM。
这些是硬件层面就并行角度看的不同。总之在这样的异构系统中Host做串行工作,Device做并行工作。
Profiling
目的是找到程序中最耗时函数。有很多Profiler工具,比如gprof
:
1 | $ gcc -O2 -g -pg myprog.c |
其中genTimeStep
函数是最耗时的。所以是我们优化对象
Strong Scaling & Weak Scaling
这是两类不同的问题,还有两者的混合问题。
了解这里的目的是啥,是为我们的加速设置一个期望值,并且计划一个增强并行化的策略。
Strong scaling 表示待解决的问题总体大小是固定的,当使用更多的处理单元时,解决该问题的时间会相应地减少。
对应的测量加速公式是
Amdahl's Law
。Weak scaling 表示每个处理单元(处理器)内所解决的问题大小是固定的,随着处理器数量的增加,问题的总量也会变大。
对应测量加速的公式是
Gustafson's Law
。
公式理解看这里
得到正确结果是所有计算的目的
一个并行系统可能遇到的关于结果正确性的问题,这些问题在一个串行系统中是不存在的:线程问题,浮点计算带来的问题,CPU和GPU的不同计算方式带来的问题。