Writeup - A GPGPU Compiler for Memory Optimization and Parallelism Management

在《The Art of Concurrency》这本书中,作者介绍了在多核处理器上进行多线程程序开发的方法,可分为四个步骤,即分析(Analysis)、设计和实现(Design and Implementation)、正确性检查(Test for correctness)和性能调谐(Tune for performance)。在已有的串行程序基础上,程序员反复进行以上四个步骤,以达到满意的性能提升或者无法继续提升性能而告终。

 

GPGPU程序的开发过程与此极其相似。例如,CUDA程序员会面向特定的应用或算法开发出一个初步的版本(naïve version)。这个版本的开发通常不考虑各种优化问题(如针对特定GPU硬件的优化),相对来说,是比较容易的。接着就是周而复始的性能调优过程。麻烦的是,每一次代码被“优化”改动之后,都必须进行正确性验证和性能测试。而且,还得反复判断是否还有优化的空间,如果有的话,还要评估需要继续付出多少时间、精力的代价以及可能有多大的回报等。这也许就是很多人觉得GPGPU开发难于学习和应用的原因。因此,人们需要一个能够将naïve版本GPU程序转换成针对某个特定GPU硬件平台的最优化版本的编译器。

 

PLDI2010上的一篇文章就向我们展示了这样一个优化编译器。这篇文章的题目是“A GPGPU Compiler for Memory Optimization and Parallelism Management”。作者抓住了GPU程序优化工作中的两个关键问题。一个是,如何有效利用GPU的存储层次结构(memory hierarchy);另一个是,如何正确的对并行任务进行管理和配置。

 

该编译器主要完成了以下优化工作。首先,将内存访问重组为向量数据读写。然后,判断对显存(GPU memory)的读写是否满足内存聚合访问(memory coalescing)的条件。对于不满足条件的显存读写,将其转换为以片上共享存储器作为临时存储空间的读写操作。接着,编译器会分析数据间依赖、共享关系以决定如何在相邻的线程块(thread block)之间共享数据。通过这些分析,编译器还能将一些线程合并,以获得更好的性能。更进一步,可以针对合并后的线程分配情况进行数据预取的工作。最后,编译器产生优化后的kernel代码,和调用参数(例如线程网格和线程块的维数大小等)。

 

这篇文章之所以能被PLDI录用,个人认为主要是由于其扎实的工作。在文章的第三部分谈及编译器框架和执行流程时,几乎涉及到了GPGPU编程中所有的重点问题。对于这些问题的思考和回答是GPGPU编译器设计中的重点,是能否发挥GPU强大并行处理能力的关键。对这篇文章的阅读,GPGPU程序设计人员可以循着作者的思路对已经设计好的程序进行分析,从而得到进一步改善程序性能的方案。

posted on 2010-09-08 13:45  胡是  阅读(239)  评论(0编辑  收藏  举报

导航