×
FPGA/DSP > 可编程逻辑 > 详情

认识多种处理芯片的特性和实战

发布时间:2020-05-13 发布时间:
|

以x86体系为代表的CPU已经占有了桌面和服务器处理器的绝大部分份额,而且这个趋势还在不断增强。CPU具有兼容性强、易编程、应用资源丰富、价格低廉的优势,但是在某些领域,CPU存在天然的缺陷,以FPGA、GPU为代表的硬件可以克服CPU的缺陷,因此也拥有自己的市场。

1.1 图解各类型芯片

从设计软件进行计算任务的软件工程人员的角度,可以将芯片分为CPU、GPU、FPGA和ASIC等类型。

对处理器芯片的特性和应用,理论上是软件人员具有最大发言权。但每一类芯片的使用和理解都不是一件简单的事情,以CPU为例:即使从事CPU环境的编程设计多年,也很难谈得上深入理解了CPU的设计思想。能深入各种芯片编程的软件人员更是凤毛麟角,更别谈进行分析和比较。另外一个问题是软件和硬件设计已分离多年,软件设计人员,很难深入理解芯片的设计思路,即使操作系统的设计人员也一样。而芯片的设计厂商由于利益相关,往往只宣扬各自的优点,回避缺陷,在测试对比中选择有利的测试条件,产生对己有利的测试数据。测试数据的真真假假,更加混淆了技术人员的视听。

在对各种芯片比较和研究的过程中,我们认为不应该沉湎于具体芯片的架构和设计思路,而应该关注芯片的实际应用。有两个原因支持我们的思路。一个原因是芯片的架构非常繁复,熟悉各种芯片几乎是不可能的任务。另一个更重要的原因是技术的价值在于应用。不管何种芯片设计或者架构,最终决定芯片价值的是实际的应用。从应用的角度出发,应按照易用性和经济性两个维度考察芯片。

易用性指用芯片进行编程的难度以及相关编程资源的获取难度。这个指标技术人员虽然不怎么关心,但其实对芯片发展有重大,甚至是绝对的重要性。例如在FPGA的编程实践中,相关的编程资源非常难以获得,即使获得也往往是代价巨大。比如常见的JPEG图片,相关的FPGA编解码库往往需要付出数万美元的成本,这和CPU领域大量的开源库完全不能相提并论。价格的昂贵还带来了测试和验证的繁杂。提供库资源的厂商往往需要旷日持久的沟通和谈判以及签署协议才能进行验证工作,这在很多研发项目运作中几乎是不可承受的。

经济性指提供相同性能情况下的芯片成本。芯片往往型号众多,比如FPGA芯片,既有上千美元甚至几千美元售价的高端型号,也有几美元计价的低端型号。脱离芯片成本谈论性能没有意义。需要指出的是,成本是综合的运营成本,而非单独的芯片购买成本。比如某款芯片如果性能等于CPU十倍,那么它不仅仅是顶替了十颗CPU,而是顶替了十台服务器的采购成本以及十台服务器的运营成本,考虑到实际的运营成本往往大于采购成本,后者可能更具有重要性。

1.2 芯片的分类

对常用的处理器芯片进行分类,有一个明显的特点:CPU&GPU需要软件支持,而FPGA&ASIC则是软硬件一体的架构,软件就是硬件。这个特点是处理器芯片中最重要的一个特征。

上图可以从两个角度来说明:从ASIC->CPU的方向,沿着这个方向芯片的易用性越来越强,CPU&GPU的编程需要编译系统的支持,编译系统的作用是把高级软件语言翻译成机器可以识别的指令(也叫机器语言)。高级语言带来了极大的便利性和易用性,因此用CPU&GPU实现同等功能的软件开发周期要远低于FPGA&ASIC芯片。沿着CPU->ASIC的方向,芯片中晶体管的效率越来越高。因为FPGA&ASIC等芯片实现的算法直接用晶体管门电路实现,比起指令系统,算法直接建筑在物理结构之上,没有中间层次,因此晶体管的效率最高。

本质上软件的操作对象是指令,而CPU&GPU则扮演高速执行指令的角色。指令的存在将程序执行变成了软件和硬件两部分,指令的存在也决定了各种处理器芯片的一些完全不同的特点以及各自的优劣势。

FPGA&ASIC等芯片的功能是固定的,它们实现的算法直接用门电路实现,因此FPGA&ASIC编程就是用门电路实现算法的过程,软件完成意味着门电路的组织形式已经确定了,从这个意义上,FPGA&ASIC的软件就是硬件,软件就决定了硬件的组织形式。软硬件一体化的特点决定了FPGA&ASIC设计中极端重要的资源利用率特征。利用率指用门电路实现算法的过程中,算法对处理器芯片所拥有的门电路资源的占用情况。如果算法比较庞大,可能出现门电路资源不够用或者虽然电路资源够用,但实际布线困难无法进行的情况。

存在指令系统的处理器芯片CPU&GPU不存在利用率的情况。它们执行指令的过程是不断从存储器读入指令,然后由执行器执行。由于存储器相对于每条指令所占用的空间几乎是无限的,即使算法再庞大也不存在存储器空间不够,无法把算法读入的情况。而且计算机系统还可以外挂硬盘等扩展存储,通过把暂时不执行的算法切换到硬盘保存更增加了指令存储的空间。

处理器芯片各自长期发展的过程中,形成了一些使用和市场上鲜明的特点。CPU&GPU领域存在大量的开源软件和应用软件,任何新的技术首先会用CPU实现算法,因此CPU编程的资源丰富而且容易获得,开发成本低而开发周期,而FPGA&ASIC编程需要的资源通常很难获得,这些资源往往以IP(intellectual property)的方式授予和收费,授予的周期往往很长而且需要签署法律协议,而费用也很昂贵。导致FPGA&ASIC的开发成本高而且周期很长。

1.3 CPU架构和编程设计

无论是x86体系为代表的繁杂指令系统(CISC)CPU还是精简指令系统(RISC)CPU,其核心都是执行一套指令系统。x86体系的CPU不断更新换代,不断提升主频,采用更先进的工艺和新架构,目的就是为了更高性能地执行x86指令。因为X86系列的CPU应用广泛,已经成为事实上的标准,本文所指的CPU特指X86系列的CPU。

从CPU内部结构观察,大致可分为控制器和执行器,再加上存储管理部件MMU以及总线接口部件。控制器不断从存储器取出指令,进行指令译码,执行器从译码完成的指令队列中取出译码指令执行。各个功能部件既能独立工作,又能与其他部件配合工作,下图给出了CPU各个部件之间的指令操作流水图。

指令系统是计算机系统发展中的巨大进步。借助指令系统,高级语言的出现成为可能,大大方便了计算机的应用。但是事情的另一面是使用指令系统后,所有的计算任务都要翻译为指令,执行一个简单的计算任务可能就需要多条指令完成。从晶体管的角度来看,简单的计算任务可能就需要众多的晶体管共同参与。为提升性能,采用指令系统的CPU,其性能设计出发点是增强指令执行的效率。

以前CPU的架构设计一直围绕如何增强指令执行的效率,为此采取的措施是不断提升主频、加多流水线(奔腾首次应用了双路流水,而现在的CPU往往拥有20以上的流水数目

)以及增加CPU的cache提升取指令的效率(早期奔腾芯片拥有几十K的缓存,而至强E5的三级缓存超过10MB,甚至可达到30MB)。近几年,CPU的架构更加重视多核的应用,期望通过多核实现更高的性能。

CPU设计出发点是增强指令的运行性能,因此CPU的核心功能强大,占用的晶体管资源庞大,具有很高的运行效率,因此CPU的多核不可能做到非常多。目前顶级的X86 CPU具有十多个核心,而GPU已经达到几千个核心。

对编程设计来说,如果线程完全独立的执行计算任务,线程间数据不存在共享和竞争关系,那么并行效率可以达到线性效果。不过现实中的编程,有很大一类是单任务的并行化,即将一个繁杂的任务通过多核并行执行来加速,那么就面临两个困难:一个是将任务并行化之后面临多线程之间的切换代价。因为CPU核心功能强大,因此操作系统切换线程时需要CPU内部大量的状态寄存器置位,所以线程之间切换是代价很大的操作(实测中,线程切换大概需要几十微秒),如果计算任务的执行时间小于这个数字,那么多线程执行对性能提升可能并无收益,甚至可能效率反而下降。

另一个问题是任务执行中数据的依赖关系。如果计算任务中某部分必须利用前面部分的计算结果,即存在数据依赖性,那么就必须等前面部分计算完成才能执行后面的计算,而不可能并行计算。数据依赖是计算中经常遇到的场景,编程设计需要调整代码结构尽量减少相关性提升并行性。

1.4 GPU的架构和编程设计

GPU(图形处理器)这个概念最早是显卡厂商Nvidia公司提出来,如它的名字所象征的意义,主要是为图形处理而设计。图形处理计算的特征表现为高密度的计算而计算需要的数据之间较少存在相关性。下图展示了GPU和CPU设计的不同之处。

图 CPU架构和GPU对比

如图所示,GPU的设计出发点在于GPU更适用于计算强度高、多并行的计算。因此,GPU把晶体管更多用于计算单元,而不像CPU用于数据Cache和流程控制器。这样的设计是因为并行计算时每个数据单元执行相同程序,不需要繁琐的流程控制而更需要高计算能力,因此也不需要大的cache容量。

图 GPU内部结构

如上图所示,GPU的架构围绕流处理器(SMX)阵列构建的。 流处理器能同时并发执行上百线程。指令流水线化以利用单线程内的指令级并行,与CPU核不同,GPU指令顺序发射,没有分支预测和猜测执行。

流处理器以32个为一组创建、管理、调度和执行并行线程,这32个线程组称为束(warps)。束内包含的不同线程从同一程序地址开始,但它们有自己的指令地址计数器和寄存器状态,因此可自由分支和独立执行。

束每次执行一个相同的指令,所以如果束内所有32个线程在同一条路径上执行的话,会达到最高效率。如果由于数据依赖条件分支导致束分岔,束会顺序执行每个分支路径,而禁用不在此路径上的线程,直到所有路径完成,线程重新汇合到同一执行路径。分支岔开只会在同一束内发生,不同的束独立执行不管它们是执行相同或不同的代码路径。

需要注意的是,GPU的线程概念和CPU的线程概念不同,CPU有虚存概念,线程具有自己的线程空间和页表项,还包括CPU的诸多状态寄存器。因此CPU的线程功能更强大,切换线程的代价也更高,而GPU的线程可以被看做一些计算指令构成的计算块,它们的调度、执行和切换要简单的多。从一个线程的执行上下文切换到另一个线程的执行上下文没有消耗,线程之间的切换是硬件切换,消耗的时间几乎可以不考虑。

计算任务中可能存在串行的部分。串行指不可并行、必须顺序执行的计算部分。这种串行部分极大的降低了任务的并行度和计算性能。在后续的实践例子中,就遇到了这样的串行部分。

单独的GPU缺乏必要的环境,没有外部设备和操作系统的支持,不能和网络或者本地硬盘交换数据,因此在实际应用中,GPU总是要和CPU搭配使用,共同构成编程的环境,这种编程称为异构编程。异构编程不可避免CPU管理的内存和GPU管理的内存之间的数据交互,数据交互的效率极大程度上将影响GPU的运行效率。

1.5 FPGA的架构和编程设计

FPGA不采用指令和软件,是软硬件合一的器件。对FPGA进行编程要使用硬件描述语言,硬件描述语言描述的逻辑可以直接被编译为晶体管电路的组合。所以FPGA实际上直接用晶体管电路实现用户的算法,没有通过指令系统的翻译。

FPGA的英文缩写名翻译过来,全称是现场可编程逻辑门阵列,这个名称已经揭示了FPGA的功能,它就是一堆逻辑门电路的组合,可以编程,还可以重复编程。不能重复编程的FPGA也有,主要是基于反熔丝技术,主要用于军事用途。下图展示了可重复编程FPGA的内部原理图。

图 FPGA内部结构图

FPGA内部可以分为可配置逻辑模块CLB、输入输出模块IOB和内部连线等三个部分。IOB是FPGA输入输出的接口,提供芯片和外界电路的连接,完成不同电气特性对输入输出信号的驱动和匹配。

CLB是FPGA的基本逻辑单元。CLB的实际数量根据芯片种类的不同而不同,以xilinx公司生产的早期FPGA Virtex5系列为例,每个CLB包含两个silce。每个slice内部包含4个查找表(LUT)、4个触发器和多路开关等资源。

数字逻辑电路从原理上,是通过时序部件和组合逻辑来完成一系列的功能,而FPGA通过芯片内部众多的CLB单元提供了众多的组合逻辑和时序逻辑。因此通过配置CLB就可以实现各种不同的功能。

本文关注的重点不是FPGA的硬件原理,也不是FPGA逻辑设计的技巧和语法,而是从并行计算的角度分析多种芯片和CPU程序设计的特点。

1.5.1 FPGA编程和CPU编程的特点

CPU编程和FPGA编程最大的不同之处是前者是软件模式,而后者是硬件模式。软件模式意味着代码之间是串行模式,代码之间有严格的执行顺序(不考虑指令乱序执行的影响),而硬件模式则意味这代码之间是并行模式,每一条语句,经过编译(在硬件领域,编译被称为综合)之后就是一个真实的逻辑电路。通过一个具体的例子可以更准确观察到软件模式和硬件模式的区别:

对于上面软件模式的代码,这两条语句之间是串行执行的(不考虑指令流水),经过编译之后,CPU先执行第一条语句,完成a变量的赋值运算,然后执行第二条语句,执行d变量的赋值运算。

如果后续没有对变量a和d的再次赋值,那么变量将始终保持当前的赋值不变。

上面语句是FPGA硬件的赋值语句。和CPU软件模式的执行方式不同,上面语句经过综合后,将形成两个逻辑电路,一个电路的输入是b和c,输出是a,而另一个电路的输入是e和f,输出是d。这两者之间是完全独立的,彼此并行而没有任何的顺序关系。

另外一点和CPU执行模式不同的是,只要输入端b、c或者e、f有任何的变化,那么输出端a或者d也立即变化,不需要再次的赋值。从硬件角度很容易理解这一点,因为FPGA的硬件描述语句被生成为逻辑电路,它是实实在在的存在并且一直执行,而CPU的指令被执行之后,除非被加载到执行单元再次执行,否则不会自动再执行。

使用FPGA编程,最大的难点在于将原有的串行思路转变为并行思路。由于人脑的思维模式更接近串行模式,所以用并行模式实现算法和功能的时候,通常困难比串行模式来得大。除此之外,还有如下特性不同:

FPGA硬件具有资源占用率的概念。FPGA编程最终要用逻辑电路实现,因此复杂的算法需要耗用更多的逻辑电路,如果使用的逻辑电路超过芯片的资源是无法实现的。这个特性和CPU完全不同,CPU的程序存储在外部存储中,执行时从外部存储载入内存执行。内存和外部存储的容量远远超过算法需要的存储量,基本不可能出现资源不够用的情况。

FPGA通常运行的时钟频率远小于CPU的时钟频率。对FPGA编程的过程,实际是将芯片内部逻辑电路连接起来实现算法和功能的过程。从FPGA的结构可以发现,FPGA是固定排列的门电路阵列,逻辑电路固定的排列方式决定了编程过程有大量的冗余电路没有利用,走线也不能够充分的精简。因此当前主流FPGA芯片编程通常运行时钟频率为200Mhz~300Mhz,而CPU的运行频率已超过Ghz的关口,现代主流的X86 CPU的时钟频率甚至超过3Ghz。

1.6 ASIC的架构

ASIC和FPGA类似,都是用门电路资源实现固定的算法,不同之处是FPGA是固定排列的门电路阵列,固定的排列方式决定了编程过程有大量的冗余电路没有充分利用,造成门电路资源的浪费,而ASIC是经过专门优化之后的门电路布局,相比较FPGA精简的多。根据厂商的提供的资料,实现同等功能FPGA所需的门电路数目可能比ASIC高10倍。

从使用方式来比较,FPGA可以重复编程,而ASIC一次编程后无法更改。由于FPGA可重复编程的灵活性,设计ASIC芯片多数时候会先用FPGA实现逻辑功能,然后基于FPGA的结果进行优化和整合,得到最终的ASIC芯片需要的电路设计。

在真正的实践中,并没有进行ASIC的设计和实际的制造,这是因为ASIC的设计和制造非常昂贵,和合作厂商沟通的结果大概需要百万美元的投入。ASIC芯片的昂贵决定了它不可能在小规模应用的场合出现,而必须是大规模(达到百万以上的量级)的应用场景才可以分摊ASIC的昂贵投入取得经济上的合理性。这种特性导致一个有趣的结果,一种计算算法初步启动时常常使用FPGA作为硬件载体,利用FPGA承载算法,随着规模扩张,就有商业性的ASIC芯片出现。一旦规模达到经济上的合理,ASIC芯片的成本就远小于FPGA的成本并取代FPGA的地位。

一个事实就是PCIE SSD的应用。早期的PCIE SSD都是使用FPGA作为内部算法的硬件载体,而2014年以来随着PCIE SSD应用的规模化,已经有ASIC芯片出现并在一些PCIE SSD的产品中应用。后续ASIC芯片很可能替代FPGA在PCIE SSD的应用。

1.7 计算实践和对比

为比较各种芯片的计算性能,以jpeg格式的图片进行解码和重新编码的计算为例子。下图展示了jpeg图像处理的算法过程。

 

jpeg图像的压缩过程:所有的图像数据首先要进行色彩空间的转换,从RGB色彩空间转换为YUV色彩空间。然后将图像分割为8像素X8像素的图像块,对每个图像块进行离散余弦变换(DCT),然后对变换后的数据量化得到量化值,最后对量化值进行墒编码,得到压缩后的图像数据。

而jpeg图像的解码过程则是编码过程的逆向过程,首先对压缩的图像数据进行墒解码,得到量化之后的数据,然后执行反量化获得量化之前、离散余弦变换之后的数据,最后进行反离散余弦变换,获得原始图像数据。

1.7.1 CPU的实践和性能

对比测试的项目以每秒钟jpeg图片解码然后重新编码的性能为准,对单张图片循环重复计算,单位为张数。CPU计算平台采用的处理器为至强E3-1270,CPU计算平台使用的转码软件是imagemagic-6.8.6,多进程并发循环执行。下表给出CPU的性能数据。

1.7.2 GPU的实践和性能

利用GPU进行图片解码和再编码时,首先遇到了顺序执行的问题。JPEG解码里面的墒解码器使用的是霍夫曼解码。霍夫曼解码在解码图像数据时候,依次处理一个个图像块,块之间没有分割标志,因此存在数据依赖关系,必须把前面图像块的数据解码完成,才能处理下一个图像块。这种必须顺序执行的计算部分GPU运行效率非常低,如果霍夫曼解码在GPU里面完成,整体效率甚至不如CPU。我们和Nvidia公司的软件团队讨论了这个问题,最后确定的方案是将霍夫曼解码部分由CPU完成。使用GPU的异构编程应当被看做是CPU的计算辅助单元,共同和CPU完成计算任务,由于架构和配套资源的特点,很难把GPU当作完整的解决方案。

第二个重要的问题是内存的分配和管理。以操作系统的角度来看,异构编程其实是对外部设备的编程,软件代码可以分成两部分,一部分在CPU上面执行,另一部分在GPU上执行。GPU的内存分配其实是对设备内存的分配,这种分配操作运行性能很低,严重影响整体计算的效率。在实际测试的代码中,将所有的设备内存分配都在开始时候一次完成,避免实际使用时的内存分配。数据从CPU内存复制到GPU的设备内存后,才能进行高性能计算。因此需要减少内存的复制时间,尽量使复制过程和GPU的计算叠加起来,形成流水式的操作。

使用GPU的异构编程,需要时刻关注GPU的利用率指标。这个指标代表GPU的繁忙程度,如果利用率很低,说明没有充分利用GPU内部的流处理器,存在流处理器较多时间空闲的情况,就需要调整和优化代码结构。一般说来,GPU的利用率应该大于80%,这是才比较充分的利用了GPU的性能。

最终的测试是和Nvidia公司的软件团队共同完成,实验性能得到了Nvdia公司的认同。下表给出GPU对JPEG图像再编码的性能数据。

1.7.3 FPGA的实践和性能

FPGA是一个单独的芯片,为了能在服务器环境使用FPGA芯片,需要设计一张FPGA计算卡,该卡使用PCIE接口和主机连接,卡上安装一片xilinx v7-690T的芯片,同时具有2GB的DDR内存。FPGA编程没有操作系统的支持和辅助,因此FPGA内部的资源必须用户自己管理,比如FPGA访问DDR内存的数据,必须通过硬件逻辑来实现,FPGA芯片和外部设备之间的数据交换也必须全部由使用者设计硬件逻辑实现功能,比如通过PCIE接口将主机内存复制到FPGA卡内的DDR内存等。

而且FPGA软件设计的生态环境和CPU的环境不同,通常FPGA设计没有大量可用的开源软件。即使有一些公司提供商业的解决方案,费用一般也很昂贵。实际上在硬件设计领域,一般都流行商业授权的模式。商业公司通常将开发的硬件逻辑打包为IP(intelligence property),有购买IP意向的使用者和商业公司谈判使用模式和费用,谈判完成前一般不提供试用版本。

为了解决FPGA编程困难、生产效率低的问题,我们创建了一个FPGA编程框架,利用框架提供用户需要的控制和数据,用户只需要聚焦于算法和功能,而不必关心底层功能的实现。FPGA编程框架弥补了FPGA 没有操作系统支持的弱点,其实质上类似一个小型的操作系统,实现对资源的管理和使用。如下图所示:

上图绿色部分展示了FPGA编程框架的构成,当前编程框架包含对PCIE接口协议的封装、DDR内存的存取和多路仲裁、DMA功能、邮箱消息接口等。编程框架里面包含了下列的重要部件:

PCI设备配置空间:设置PCIE设备配置空间的信息,包括PCI设备ID,制造厂商和设备IO端口以及IO mem资源
DMA:启动DMA功能,从主机内存物理地址复制数据到FPGA卡DDR内存的指定地址,或者从FPGA卡DDR内存的指定地址复制到主机内存物理地址。

DDR:从FPGA卡DDR内存指定地址读数据,每次读出64bit数据。或者往FPGA卡DDR内存指定地址写数据,每次写入64bit数据。

邮箱:邮箱提供主机和FPGA芯片之间的消息接口。

中断资源:中断接口管理和控制,通过接口可以触发一个系统中断。

在FPGA程序实现时最重要的问题就是资源利用率。FPGA和CPU不同,如果资源没有限制,FPGA理论上可以部署足够多的计算单元,性能可以达到无限。在图片转码的实践中,基于690T的芯片,实际上部署了30路的编解码核心,这时资源利用率达到70%。下表给出FPGA的性能数据。

1.8 结论和综述

从整个实践的过程理解,FPGA&GPU芯片的使用是很复杂的过程。性能和性价比是否具有优势需要针对业务的计算类型设计程序和优化,并进行实际的验证得出结论。希望简单和一致性的结论没有可能,而厂商的结论多半并不可信,和实际验证的数据差别巨大。现实是硬件、环境和算法资源都很缺乏,这可能是异构编程应用不广泛和困难的原因。脱离了CPU的支持,使用GPU&FPGA等芯片的异构编程困难太多,如果像CPU集成GPU一样,同样在CPU内部集成FPGA功能,方便用户的选择和使用,将大大推动各种场景的实际应用。


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
FPGA VS ASIC.究竟何时能取代后者?