C2CUDA
目录
目标分析
首先,目标是将C语言转化为CUDA加速程序的运行,从这里我们引出两点需要探究的内容是:
- CUDA加速的原理是什么?
- C语言中的什么部分可以被CUDA有效的加速?
CUDA加速的原理
2006年,NVIDIA推出了统一计算设备架构(CUDA),使任何计算工作负载都能不受图形API的限制,利用GPU的吞吐量能力。
——CUDA编程指南
从上面的引用可以看出,CUDA设计的目的是利用GPU的吞吐量能力(单位时间内系统能处理的任务总量(或数据量))
而CUDA 的核心逻辑是将大规模并行的软件逻辑(Thread)映射到大规模并行的硬件资源(Core)上
因此最核心的原理就是并行,因此C语言中的什么部分可以被CUDA有效的加速?
C语言中可被有效加速的部分
最核心的就是可以并行的部分,那么在一个串行的C语言代码中有什么可以并行呢?
- 数据并行:在C 语言中,循环(Loop)是数据并行最主要、甚至几乎是唯一的显式表现形式。
- 任务并行:代码中互不相关的函数调用或代码块也可以并行, 任务并行的规模通常很小(比如同时跑 2-4 个不同的任务),相比于循环动辄上百万次的迭代,它带来的加速效果远不如循环并行明显
- 指令级并行: 这种并行通常由硬件和后端编译器(如 NVCC)自动优化,通常不需要关注它。
因此,核心目标就是将C语言中的循环利用CUDA并行化运行在不同硬件上。
[!IMPORTANT]
将循环并行化意味着不同循环循环迭代之间的运行顺序是不保证的!
CUDA 执行线程是并发的,硬件调度是不确定的。迭代 \(100\) 可能比迭代 \(1\) 先执行,也可能同时执行。这本质上就是一种极端的“重排序”。
因此要确保并行化有效(不能改变程序的最终结果),就必须识别什么循环可以用并行。这里从一个定理引入
定理 迭代重排序 一个变换重排\(k\)层循环迭代的顺序,此外不做任何其他的改变,如果该循环不携带依赖,那么它是有效的。
**——现代体系结构的优化编译器 ([美] Randy Allen) **
这个定理可以说是本项目研究的基石,项目的入口,因为只有确定什么样的循环迭代能够进行迭代重排序我们才能使用CUDA对其进行并行化。
由此定理引出的概念:循环携带依赖、循环携带依赖的层
到此为止, 我们已经知道项目要如何进行了, 使用定义循环携带依赖判断循环嵌套是否有依赖以及依赖所在的层(对于某些存在循环携带的层, 利用循环变换能够转化为不携带依赖的层), 根据定理迭代重排序对不存在携带依赖的层利用CUDA并行化
定义定理
[!NOTE]
定理皆来自于现代体系结构的优化编译器 ([美] Randy Allen)
定义 循环携带依赖 语句\(S_2\)对语句\(S_1\)有一个循环携带依赖,当且仅当\(S_1\)在迭代i中引用单元\(M\),而\(S_2\)在迭代j中引用\(M\),且\(d(i,j)>0\)(即\(D(i,j)\)包含一个“ 0 \\= , & \text{如果 } \mathbf{d}(i, j)_k = 0 \\> , & \text{如果 } \mathbf{d}(i, j)_k < 0\end{cases}\]
定义 循环迭代号 对任意一个循环,其中循环索引 $ I $ 以步长 $ S $ 从 $ L $ 步进到 $ U $,一个特定迭代的(正规化)迭代号 \(i\) 等于值 $ (I - L + S) / S $,其中 $ I $ 是该迭代中索引变量的值。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |