内容简介:认识多种处理芯片的特性和实战(上篇)
作者 | 高剑林
编辑 | 京露
高剑林,腾讯架构平台部,平台开发中心基础研发组组长。先后从事过通讯设备的开发和存储设备的研发工作。目前致力于一体化的涉及—从硬件和软件的结合,以及OS多个层面综合考虑系统设计,找出最优路径的设计思想。
以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。
相关阅读: 接认识多种处理芯片的特性和实战GPU&FPGA&ASIC&CPU (下篇)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Tensorflow Rust实战上篇
- 系统架构系列 (三):业务架构实战上篇
- 威胁情报相关标准简介 (上篇)
- 【前端面试分享】- 寒冬求职上篇
- 认证授权方案之授权揭秘 (上篇)
- 流式处理框架storm浅析(上篇)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。