异构加速知识

本文介绍了异构计算的基础知识,包括CPU、GPU、FPGA和ASIC等计算单元的特性,以及CUDA和OpenCL等编程框架。异构计算通过结合不同类型的计算单元,克服了CPU性能瓶颈,提高了数据中心的计算效率。OpenCL提供了一个统一的编程模型,包括平台模型、执行模型和内存模型,使得开发者可以更好地利用异构硬件资源。
摘要由CSDN通过智能技术生成


本文主要介绍异构技术的产生背景、异构计算的编程模型和执行流程。

1 异构加速

通过提升CPU时钟频率和内核数量而提高计算能力的传统方式遇到了散热和能耗瓶颈。而与此同时,GPU等专用计算单元虽然工作频率较低,但具有更多的内核数和并行计算能力,总体性能/芯片面积的比和性能/功耗比都很高,却远远没有得到充分利用。人工智能以及其它新兴应用领域对于计算量的需求超过了通用CPU摩尔定律的发展速度,而异构计算的性能增长速度能够满足这些新兴的方向和趋势,可以预见,异构计算会在今后的数据中心中占据越来越多的份额。

异构计算主要是指使用不同类型指令集和体系架构的计算单元组成系统的计算方式。常见的计算单元类别包括CPU、GPU、DSP、ASIC、FPGA 等。CPU的设计让其比较擅长于处理不规则数据结构和不可预测的存取模式,以及递归算法、分支密集型代码和单线程程序。这类程序任务拥有复杂的指令调度、循环、分支、逻辑判断以及执行等步骤。GPU擅于处理规则数据结构和可预测存取模式,可以同时执行成千上万的线程。而FPGA的硬件逻辑可以通过软件动态改变,从硬件的角度来适配软件,从而获得更高的计算性能,更高并行性、能效比。FPGA拥有更丰富的计算资源组件,从而能够满足更多并行计算需求,并且能够充分发掘软件算法中的并行性,降低功耗。

异构计算的实现架构通常是CPU+ GPU/FPGA/ASIC,主要由CPU完成不可加速部分的计算以及整个系统的控制调度,由GPU/FPGA/ASIC完成特定的任务和加速。目前 “CPU+GPU”以及“CPU+FPGA”是最受业界关注的异构计算平台,它们最大的优点是具有比传统CPU并行计算更高效率和低延迟的计算性能,能够很好的满足人工智能、高性能数据分析、金融分析等计算密集型领域的计算需求。每个异构的方案都有其优缺点,如下表所示。

方案优势劣势
CPU+GPU并行度和计算效率都比较高具备一定的可编程性,但不如FPGA方案灵活
CPU+FPGA硬件可编程,并行度和能效比比GPU方案更高价格昂贵,不便于大规模部署,而且开发难度较大
CPU+ASIC并行度和能效比比前两个方案更高,价格便宜硬件完全固定,不具备可编程性,而且开发周期长

纵观整个体系结构的发展,原始的架构是CPU+IO的架构,CPU完成所有控制和计算任务,结构简单,但是效率不高,已无法满足算力的发展需求。现阶段以发展出CPU+GPU+FPGA+ASIC的多元算力融合的架构,由CPU完成任务的调度,GPU、FPGA、ASIC等计算单元完成具体的计算任务,计算效率高,能耗低。目前已发展出了DPU芯片,可以简单的理解为同时具备CPU和FPGA功能的芯片,可以提供网络、存储、安全等基础设施。在未来,会逐渐形成以DPU为中心,CPU、GPU、FPGA等多种计算单元协同处理的体系结构。而在更远的未来,或许会将所有的计算单元都集成到同一块芯片中,完成所有的管理、调度和计算任务。

在这里插入图片描述

2 编程框架

要让不同体系结构的计算单元能够分工合作去完成一个任务,一个统一的编程框架是必不可少的。目前用户最多、应用范围最广的异构编程框架是CUDA编程框架, 仅次于CUDA编程框架的还有OpenCL编程框架。CUDA编程框架是英伟达于2007年推出的异构计算编程框架,它的出现将GPU带入通用计算领域,目前在大数据、人工智能方面有广泛应用。但是CUDA只可以运行在英伟达公司GPU设备上,不兼容AMD等其他公司GPU设备,因而CUDA程序的可移植性很差。

继CUDA之后,苹果公司在2008年提出了OpenCL编程框架,最初目的只是用 于开发GPU通用计算软件。苹果随后将此提案交由非盈利组织管理,并在当年发布 了OpenCL 1.0技术规范。该规范由于其开放性,得到了AMD、英特尔、英伟达等大多数公司的支持,并在随后的发展中逐渐加入了对FPGA、DSP等并行计算设备的支持。因而OpenCL具有非常 好的通用性与可移植性,编写完成的OpenCL程序可以跨平台、跨设备运行,但是如果要获得高运行效率的程序,需要针对运行设备的特点对程序进行特别优化。

OpenCL利用一系列工具与函数将底层实现封装起来,大大减轻开发人员的编程难度。为了具有很好的通用性和易开发性,OpenCL制定了一套严格并且抽象的编程模型,用以对底层硬件进行抽象描述,按抽象层次高低可以大致分为三种:OpenCL平台模型、OpenCL执行模型、OpenCL内存模型。

2.1 平台模型

OpenCL平台模型是对OpenCL框架下的异构硬件架构的高层次抽象描述,定义OpenCL 异构系统是由一个宿主机(Host)连接一个(或多个)OpenCL设备(Device)组成,宿主机用于系统任务调度,OpenCL设备用以处理系统里的计算任务。宿主机一般是控制逻辑丰富的CPU芯片,承担搜索系统OpenCL设备、管理调度、传输数据给设备的任务;OpenCL设备是支持OpenCL标准的GPU、FPGA、DSP 等芯片,作为宿主机的从设备,处理宿主机分配的计算任务。先在能调用的芯片中选定一个CPU芯片作为宿主机,其他的芯片作为OpenCL设备,各芯片之间通过PCIe或其他高速协议进行互联通信。每个OpenCL设备内含多个(或一个)计算单元(Compute Unit),每个计算单元内含多个(或一个)处理单元(Processing Element),处理单元就是OpenCL框架下处理计算任务的最小单元。

在这里插入图片描述

2.2 执行模型

OpenCL执行模型是对OpenCL硬件执行的较低一级抽象描述,定义宿主机运行管理内核(Kernel)执行的主机程序,具体包括创建上下文(Context)、提交数据以及全局索引空间大小等;OpenCL设备运行内核程序,在宿主机提交的全局索引空间范围内执行所有的工作项(Work-item)。OpenCL执行模型是与OpenCL平台模型相关的,是相较于OpenCL平台模型抽象层次较低的描述。一个可执行的OpenCL程序需要包含以下两部分,管理调度的宿主机程序和负责计算实现的内核程序。

在这里插入图片描述
宿主机程序在宿主机上运行,负责调度任务和数据通信,运行时会先查询可用平台与可用 OpenCL设备集,然后为选定的可用OpenCL设备建立名为上下文(Context)的数据结构。在OpenCL 框架下,上下文是个很重要的用来管理内核的工具,宿主机程序会利用创建的上下文建立命令队列(Command queue)、程序对象(Program)和内存对象(Buffer)。

命令队列用来管理创建的命令在OpenCL设备上的执行情况,OpenCL框架支持两种命令执行方式,顺序执行和乱序执行,顺序执行下命令按照提交顺序执行,乱序执行则不必按照提交顺序执行;程序对象用来封装内核函数,一个程序可能包含多个内核,而内核用于宿主机程序向在OpenCL设备上执行的内核程序传递参数;内存对象是储存一个线性字节序列的内存对象,一个运行中的内核程序可以通过一个指针来访问,宿主机也同样可以对这个内存对象进行读写。

内核程序在OpenCL设备上运行,负责计算任务的具体实现,当设备接收到宿主机程序传递过来的执行命令,就会启动内核程序,在宿主机提供的全局索引空间内,处理内存对象里需要计算的数据。全局索引空间是一个多维空间,空间里的每个坐标为整数的点都会对应一个内核实例,也就是工作项(Work-item),所以每个工作项都会在多维空间内有一个唯一的标识,标识与坐标一致,也就是全局ID (Global ID)。这些工作项在内核执行时会执行相同的代码,只是执行路径和计算的数据会不同。在OpenCL标准里工作项可以完全并发执行,但是在实际的实现里并不是这样,因为每个工作项的执行都需要上节平台模型里提到的一个处理单元,而实际程序中工作项的数目常常多于设备处理单元数。因而在实际的程序运行里,工作项的并发执行设计取决于设备的硬件情况。

在全局索引空间里,工作项会被再组织成工作组(Work-group),工作组组成整个空间。因此工作组是相比工作项更粗粒度的对全局索引空间的描述,每个工作组都会被系统分配不同的标识,也就是工作组ID (Group ID)。工作组内部也会有局部ID (Local ID),这是用以标识工作组内部的工作项,每个工作项的局部ID都是不一样的。因而在索引工作项时可以有两种方法,一种是直接索引它的全局ID,另一种就是通过它的工作组ID以及工作组内的局部ID来索引。
在这里插入图片描述

2.3 内存模型

OpenCL内存模型是对内核程序使用到的内存区域的抽象描述,定义了各内存区域的特性,以及内核程序与宿主机程序对各内存区域的分配、访问能力。OpenCL内存模型将内核程序能够访问的内存区域分为四种,分别为全局内存(Global memory)、常量内存(Constant memory)、局部内存(Local memory)和私有内存(Private memory),这四种内存的物理实现都在OpenCL设备上。

  • 全局内存:宿主机与内核都可以访问读写的内存区域,内存对象由宿主机声明并分配大小,用于宿主机与内核间的数据传输。
  • 常量内存:在物理上属于全局内存的一部分,同样由宿主机声明并分配大小,用以与内核的数据传输,但是在内核中的声明标识符与全局内存不一样。并且内核只可读,不可进行写入操作,内部数据由宿主机写入,存放在整个内核运行过程中不会变化的数据。
  • 局部内存:用于存放一个工作组内所有工作项共享的数据,工作项对其访问速度大于访问全局内存的速度,并且宿主机无法访问读写。
  • 私有内存:用于存放单个工作项的数据,仅属于单个工作项,其他工作项无法访问,由内核程序声明并分配大小,对宿主机不可见,是整个内存模型里工作项访问最快的内存区域。

以FPGA内存系统为例,全局内存与常量内存就是FPGA设备DDR内存,本地内存就是片上嵌入式RAM块,私有内存就是片上寄存器。FPGA设备在工作时,宿主机会先将数据提交给全局内存,内核中的计算单元会根据程序要求,将数据从全局内存读取至本地内存内,或读取后直接计算处理掉。
在这里插入图片描述

3 执行机制

OpenCL系统是主从结构,需要一个宿主机管理系统的进行,从设备在宿主机的管理下处理宿主机分配的任务。当前FPGA大致可以分为两类,一类是集成ARM处理器的片内异构FPGA,一类是未集成的FPGA。对于有ARM处理器的FPGA来说,ARM处理器可以做为宿主机,剩余逻辑做为从设备,OpenCL实现机制与无ARM处理器的FPGA大体相同,因而这里不详细介绍,本小节将主要介绍以外部处理器做为宿主机,FPGA做为从机的OpenCL执行机制。

OpenCL程序由两部分组成,在宿主机上运行的宿主机程序,在从设备FPGA上运行的内核程序。两个程序的源码编写不分先后,但是编译时需要先编译内核程序源码,因为宿主机程序编译时会用到内核程序的编译结果。OpenCL离线编译器由FPGA供应商提供,编译内核程序的时间较长,一般从半小时到数小时不等,这与内核程序大小和编译用到的内存多少有关。编译完成后会得到一个可配置的FPGA镜像,以英特尔FPGA为例,这个镜像是包含了sof 文件的aocx文件,同时编译也产生了转换后的底层源码和Quartus II完整工程,包括大量的底层配套的各种IP源码,通过将aocx文件烧写进FPGA就完成了对FPGA内部的电路配置。利用先前编译得到的aocx文件,以及配置了OpenCL库环境的C/C++编译器,就可以编译宿主机程序,会生成一个可执行程序,在宿主机直接运行可执行程序就可以得到计算结果。

在这里插入图片描述
在OpenCL库的支持下,宿主机程序调用OpenCL函数,根据选用的FPGA平台创建上下文,上下文是管理内核程序的关键,通过上下文可以创建程序对象、命令队列、内存对象。程序对象用来封装内核函数在宿主机端的镜像,宿主机通过这个内核函数镜像,向从设备FPGA执行的内核函数传递参数;命令队列用于管理创建的命令在从设备上的执行情况,所有命令都需要在命令队列里排列等待,按照一定的顺序发往从设备执行;内存对象是宿主机与从设备通信的媒介,宿主机将需要从设备处理的数据缓存到内存对象里,从设备再从内存对象里读取,内存对象同样也是从设备用以存储大量计算中间数据的内存区域,需要指出内存对象是宿主机程序创建的数据结构,但它真正映射的物理对象是从设备的DDR内存。

宿主机程序创建完内存对象,设置程序向内核函数传递参数后,就会提交命令进入命令队列,让从设备开始执行内核程序,同时将数据维度和全局索引空间大小等信息告诉从设备。从设备接收到指令后,开始执行内核程序,通过PCIe与FPGA内部互连网络,把宿主机传递的数据传输到内存对象映射的地址,也就是FPGA上的DDR内存内,内核执行程序在全局索引空间内寻址,并通过FPGA内部的全局互连线访问
DDR内存。内核得到数据后,根据内核程序的代码实现把数据存入本地内存,或读取后直接计算处理,如果计算涉及浮点乘除等复杂操作,会调用DSP模块,计算得到的最终结果会写回DDR内存。在内核完成计算任务后,宿主机会通过PCIe从DDR内存读回计算结果。

设计内核程序时,会根据内核读取数据的特点来使用本地内存,本地内存相较于DDR内存离内核更近,因而其读取速度更快。如果内核从DDR内存读取的数据只使用一次或很少次,则没有必要使用本地内存,相反则需要将数据从DDR转移至本地内存存储,可以大大减少内核读取数据的时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值