赛灵思的 SDAccel 开发环境为 FPGA 提供软件应用设计流程。
赛灵思 FPGA 器件主要由可编程逻辑架构组成,能让应用设计人员利用空间和时间并行性,最大化算法性能或大型应用中关键内核的性能。位于这种架构核心的是由基于查找表的逻辑元、分布式存储器单元和乘法-累加单元构成的阵列。设计人员可以用不同方式组合这些元件,把逻辑实现在算法中,同时满足功耗、吞吐量和时延方面的设计目标要求。把 FPGA 架构元件组合为逻辑功能一直是硬件工程人员的工作范畴,这个过程更类似于汇编层面的编码,与现代软件设计实务相去甚远。虽然常用软件设计流程早已脱离汇编编码的层面,但由于 CPU 编译和 FPGA 编译之间内在的差异,FPGA 设计实践的发展步伐要缓慢一些。
在 C++PU 和 GPU 领域,硬件是固定的,所有的程序均根据静态指令集架构 (ISA) 编译。虽然 CPU 和 GPU 之间的 ISA 不同,但基本的底层编译方法是相同的。这种相似性促使设计实践从手动汇编编码向使用 OpenCLTM C、C 和 C++ 等软件开发常用的编程语言进行编译、调试和优化的设计流程发展演化。
在 FPGA 设计方面,设计人员能够为运行特定工作负载开发自己的处理架构。FPGA 的一大重要优势就是能够根据特定系统需求定制架构,但这不利于 FPGA 应用开发中采用软件开发实践方法。
六年前赛灵思开始积极的研发工作,通过开发一种把直观的软件开发设计循环引入 FPGA 的开发环境,来打破这一障碍。面向 OpenCL C、C 和 C++ 的赛灵思 SDAccelTM 能够让 FPGA 器件的应用编译、调试与优化方式类似于 CPU 和 GPU 的流程,而且在用于数据中心应用加速时,可将性能功耗比提升高达 25 倍。
软件设计人员可以使用 SDAccel 开发环境开发和加速众多功能与应用。下面介绍如何使用 SDAccel 环境实现中值滤波器应用的编译、调试与优化设计循环。
中值滤波器
中值滤波器是一种常在图像处理中用于降噪目的的空间函数(图 1)。中值滤波器使用的算法用围绕中心像素的 3x3 像素窗口,根据所有相邻像素的中值计算中心像素值。这一计算公式为:
outputPixel[i][j] =
median(inputPixel[i-1][j-1], inputPixel[i-1][j], inputPixel[i-1][j+1],
inputPixel[i][j-1], inputPixel[i][j], inputPixel[i][j+1],
inputPixel[i+1][j-1], inputPixel[i+1][j], inputPixel[i+1][j+1]) ;
编译
运用 OpenCL C 等语言编写中值滤波器函数后,就进入开发的第一个阶段——编译。在 CPU 或 GPU 上,编译是软件设计流程中的一个必要的也是必然的步骤。目标 ISA 是固定而公开的,编程人员只需关心可用的处理内核数量和算法的高速缓存缺失情况。FPGA 编译更像一个开放问题:在编译时目标 ISA 并不存在,逻辑资源还有待组合成处理架构,系统存储器架构也尚未定义。
SDAccel 开发环境中的编译器提供三项功能,可帮助编程人员应对如下这些挑战:自动在循环内的语句间和跨循环迭代提取并行性、根据对阵列的读写模式自动调用存储器架构、以及对给定 FPGA 器件内部基本逻辑元的类型和数量的架构感知能力。这三项功能对中值滤波器的源代码的重要性见图示(图 2)。
中值滤波器的运算可以表达为由一系列由两个部分组成的嵌套循环。第一个部分负责从名为“输入”的外部存储器中阵列取出数据,然后把值存储在本地阵列“RGB”中。算法第二个部分是一个围绕 getMedian 函数的“for”循环。getMedian 就是计算发生的位置。
通过分析图 2 中的代码,SDAcell 环境认为 RGB 阵列上不存在循环-承载数据依赖关系。每次循环迭代都有一个专有 RGB 副本,这个副本可以存储在不同物理资源上。从这个代码看出的 SDAccel 环境的另一大特点是对 getMedian 函数调用的独立性。
图 2 所示的算法版本在带有固定边界的“for”循环内部执行 getMedian 函数。根据滤波器的性能目标和所选的 FPGA,SDAccel 环境可以跨所有三个通道重复利用计算资源,或是分配更多逻辑,实现空间并行性,同时运行所有通道。这项决定相应地会影响如何为阵列 RGB 实现存储器存储。
从应用编程人员的角度出发,上述步骤是透明的,可视为 GNU 编译器套件 (GCC) 中的–O1 到 –O3 优化。
SDAccel 环境中的 printf 设计无需耗用额外逻辑资源即可提供此项功能。
调试
软件开发的一条公理就是应用编译不等同于应用正确。只有在应用在目标硬件上开始运行之后,编程人员才能开始发现、追踪和纠正应用中的错误,换句话说进行调试。
CPU 应用的调试是一个容易理解的问题,商业厂商和开源社区提供有大量工具来解决这个问题。FPGA 再度成为另类。应用编程人员如何才能调试好创建用于实现一段代码的功能的软件,使之实现既定性能目标呢?
SDAccel 开发环境借鉴了 CPU 环境的两个概念——printf 和 GDB 调试——来解决这个问题。
printf 功能是软件编程人员工具箱中的基本工具。每一种编程语言都会提供 printf 功能,用于显示程序执行过程中主要应用变量的状态。对 CPU 器件而言,这就同监测寄存器状态一样简单。printf 功能不占用硬件资源。
就 FPGA 的情况来说,实现 printf 可能会消耗本可用于实现逻辑功能的逻辑资源。在 SDAccel 环境中实现 printf 无需消耗额外的逻辑资源即可提供此项功能。该环境是通过将 printf 数据生成独立于解码和用户表示层来实现的。就硬件资源而言,为 printf 生成数据会占用几个寄存器,在寄存器丰富的 FPGA 架构中这完全可以忽略不计。数据解码在针对 FPGA 的驱动程序中完成。通过让主机 CPU 执行 printf 的数据解码和表示层,软件编程人员可以在基本不占用 FPGA 资源的情况下使用 printf。
从 CPU 借鉴的第二个调试技巧是使用 GNU 项目调试器 (GDB) 等工具,在代码中各处插入断点和单步执行。编程人员可以使用 SDAccel 环境的仿真模式,将 GDB 连接到正在运行的仿真流程。该仿真流程是对开发人员准备在 FPGA 器件上执行的专用硬件的仿真。在仿真流程环境下,GDB 能够观察各种变量的状态,在代码各处插入断点和单步执行。从应用编程人员的角度,这与 GDB 在 CPU 上工作的方式完全相同。
优化
完成编译和调试后,软件开发周期的下一步是优化应用。在 FPGA 上进行应用优化的原理与在 CPU 上优化应用一致。唯一差别在于方法不同。对 CPU 来说,需要细调应用代码,使之适应处理器的高速缓存和算术单元的边界。在 FPGA 中,计算逻辑是为当前应用定制汇编的。因此决定优化约束的是 FPGA 的大小和应用的目标性能。
使用 SDAccel 的软件编程人员可以借助逻辑架构的灵活性,不必了解有关硬件设计的细节,即可构建高性能、低功耗应用。
SDAccel 环境的编译器能自动优化计算逻辑。编程人员可通过对从代码调用的数据传输模式的分析来协助自动优化工作。图 3 所示的是输入和输出过程中发生的中值滤波器代码与存储器之间的读写事务处理。
图中的每条垂直线代表一个到存储器的事务处理。绿条所示的是中值滤波器函数的活动时间。从图中可以看出,虽然中值滤波器一直处于活动状态,存储器事务处理之间存在明显的间隔。这些间隔代表的是中值滤波器从一个事务处理切换到下一个事务处理所使用的时间。由于每项对存储器的事务处理只访问一个值,事务处理之间的间隔说明该应用存在严重的性能瓶颈。
解决该性能问题的途径之一是在应用代码中明示地声明从外部存储器到本地存储器的突发事务处理。图 4 所示的代码片段使用了 OpenCL C 语言内核采用的 async_work_group_copy 函数。这项功能的目的是通知编译器每项对存储器的事务处理都是一个包含多重值的突发事件。这样能够更高效率地利用目标器件上的可用存储器带宽,并减少对存储器的事务处理总数。在图 4 的代码中,async_work_group_copy 函数把 DDR 存储器中输入图像的全部行内容提交给内核数据路径内的存储器。图 5 中的存储器事务处理迹线体现了使用 async_work_group_copy 的结果。如图 5 所示,在存储器事务处理发生之前内核有一个建立时间,但这并没有体现在中值滤波器的原始代码中(图 2)。
这部分建立时间差异用于处理从代码中衍生出的逻辑。在图 2 的原始代码中,应用立即启动对存储器的单次事务处理,然后等待数据可用。与此相反,图 4 中的优化代码能判断是否需要进行存储器事务处理或是否内核的本地存储器中的数据已经可用。它还能让生成的逻辑背对背地调度存储器事务处理和覆盖读写事务处理。
不管最终器件是 CPU 还是 FPGA,特性分析都是应用开发过程中的主要组成部分。SDAccel 环境的可视化和分析器功能能让应用编程人员从内核占用、存储器事务处理和存储器带宽利用率等方面对代码修改和应用要求进行特征描述。
由编译、调试和优化 *** 作建立的设计环路是软件开发流程的基础。SDAccel 开发环境使用类似于CPU 开发环境的工具和技巧来实现这一设计环路,同时基于 FPGA 的应用加速可将性能功耗比提升 25倍,时延则缩短 50 至 75 倍。使用 SDAccel,软件编程人员无需了解有关硬件设计的所有细节,就能够充分发挥 FPGA 逻辑架构的灵活性,从而开发出高性能、低功耗应用。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)