在多核FPGA上实现MCAPI
摘要
设计和实现API需要在它的抽象级别和对系统的消耗上做出权衡。本文提供了在以FPGA为主通过PCIe与外部CPU连接的的异构多核片上系统实现多核通信API(以下简称MCAPI)的方案。为了在不同的CPU,操作系统已经硬件IP块实现统一的编程标准,MCAPI应运而生。本文讨论了使用MCAPI在三个处理器、两条总线上进行数据传输,测量其开销并且分析从PC到MPSoC做应用程序的移植所需要做的工作。最终测得库所占用的内存不超过25KB并且往返通信的延迟是递减的——比起非MCAPI的实现,只有几十个时钟周期。
关键字:并行编程,多核处理器,编程接口,FPGA
1 简介
现代嵌入式应用正朝着复杂化和由敏捷开发造成的更严格的代码重用的方向发展,其中实现过程离不开软硬件的结合,并且在产品的生命周期中也会多次改变。因此,除了硬件本身的性能外,编程模型和工具这些软件层面的支持也是必不可少的。
图一描述了本文的目的,整体的功能是使用例如基于模型的技术,并映射到物理地址从而实现包括各种处理器和固定功能硬件IP核时间的通信。此外,例如操作系统,驱动以及可兼容中间层这样的高效软件平台服务也是必不可少的。
图一:通过在处理器和固定功能的硬件模块使用统一的抽象接口来实现多任务应用程序。在本次测试中使用定制的TTA处理器已经Alterar的NIOS作为示例。
我们的目的是实现适配与软件和硬件块的抽象接口,并且保证适当的性能,比如说,小的内存和面积要求以及应用程序代码的快速移植和重新映射。
如今已经存在许多适用于片上多核编程的模型和工具,这些工具帮助在特定的平台上进行分区和映射,通常兼容的API保证了应用程序的可移植性,然而传统的多核API太过于繁冗,并且缺少对异构硬件IP块处理器的支持。
多核通信接口MCAPI为多核环境下核间通信提供比多机间通信更快、更可靠的支持。,因此,MCAPI致力于提供更轻量级和更为有效的并行计算编程接口。
我们在多核FPGA为基础的片上系统环境实现MCAPI。现在FPGA设备非常灵活,最多可以包含几十个软核处理器和IP块。主要目标是一个使用的解决方案可立即投入嵌入式产品开发。这篇论文的主要组成是:
1.在FPGA多核片上系统上实现MCAPI。
2.分析内存占用和性能开销。
3.一个可移植代码的示例。
以上三点主要内容,论文结构如下:
在第二部分,我们讨论相关的工作,在第三部分简单介绍API规范并在第四部分说明我们的实现最后两部分将展示结果并分析结论。
第二部分相关工作
API是描述系统组件间交互的抽象接口,在实践中,API是一组程序集,例如:send_data() 或者connect_channel()。这样的通用接口在高效率地开发复杂的可移植应用程序是十分有用的。相似的函数接口提供给程序员,并且他们不需要知道内部实现,例如在PC上运行Linux和NIOS无需任何操作系统。因此,大多数的开发和功能验证可以在工作站上进行并且将测试软件移植顺利的移植到多核片上系统上。然而,一些API从硬件平台做出假设,例如如何利用共享内存。
A.OpenMP,MPI 和 CORBA
OpenMP 是很多平台共享内存上——从台式机到超级计算机的多核处理器的C/C++和Fortran的API,例如UNIX和WindowsNT平台。OpenMP需要特殊的编译器支持,这一点,在另一方面使其很容易适配。代码仍然可以串行执行,与此同时并行也可以逐渐增加。
MPI是一个特殊的消息传递库的接口,与OpenMP不同的是,MPI可以在共用或分布式存储器结构中使用。然而,比起OpenMP,MPI需要做更多代码上的改变,但不需要特殊的编译器。
CORBA(公共对象请求代理体系结构)是指在计算机对象之间通信。它提供了高度抽象的接口和一些服务。现在已经尝试使用CORBA的嵌入式系统,甚至有些部分已经通过VHDL在硬件上实现,但是,对于我们的目标来说,CORBA太过于繁冗。
不幸的是在工作站环境中使用的通用解决方案可能在嵌入式系统上消耗过多的资源,这个绝对值(例如MPI ~300)可能被证明是矫枉过正并不需要消耗太多的资源。
另一个挑战是内存占用,例如,一共有8个从核的Cell宽带引擎(协同处理引擎,SPE),其中这8个核每一个核都具有256KB的本地内存,这对于使用一个完整的MPI库是远远不够的,除非使用一些裁剪过的MPI版本。
B、研究建议和实验
在几种多核处理接口建议下,我们考虑一些接近我们目标的例子。Cell 处理器就是一个有趣的平台,因为他的卫星处理器提供了良好的性能,但软件优化上就显得有些吃力。为了开发,Khunjush,Abellan和Hung已经使用并分析Cell SDK,它提供低级别的原语来访问并行资源,Hung还实现了混合动力相结合的API,包括MPI和MCAPI的部分,他们的工作是最接近我们MCAPI的实现的。
一些MPI的实现已经展示了基于FPGA的多核片上系统。Minhass使用Altera 的NIOS,Saldana和Mahr使用xilinx的MicroBlaze,已经提出了以UML2.0建模的嵌入式应用和相关的进程间通信。
Paulin等人提出了一个名为StepNP的可定制片上多核探索环境。它提供了硬件上的消息传递和多线程,以尽量减少延迟,我们将在后面的章节中的相关工作比较我们的结果。
第三部分多核通信API(MCAPI)
MCAPI主要面向核间通信而MPI和Socket主要是用于计算机间的通信。因此,MCAPI的主要设计目标是指定一个低延迟的API来保证在片上使用网络的效率。MCAPI的通信延迟和内存占用预计效果预计会比MPI或者socket显著,但是要牺牲一定的灵活性。
MCAPI的目标是提供一种具有有限的调用来保证充分的通信功能,同时它足够简单。附加的功能可以层叠在API集合的顶部。这些特定的调用被看做是功能性的一个例子,它并未映射到任一存在的实现中。
A 通信实体
MCAPI规范既是一个API也是一个通信语法规范,它没有定义哪个环节的管理,设备型号或者是约束底层使用的通信协议,这样,通过定义标准的API,它可以为应用程序提供兼容性的源代码,也可以从一个环境到另一个环境的移植(例如我们是从PC到MPSoC),MCAPI的实现也忽略了存储设备在架构上的差别。
MCAPI 通信是基于节点(node)和终端节点(endpoint)抽象,如下图2所示,MCAPI节点是可以表示许多实体,包括一个进程,一个线程,硬件加速器或者处理器和兴的逻辑概念,节点总是独特的,并且,在我们的例子中,设计时是静态定义的。
每个节点可以拥有多个类似于socket的终端节点,例如,加密节点可以从一个端点接收普通文本,并经由另一个端点发送加密数据被实施为单个线程。终端节点在定义的时候以<node_id,endpoint_id>这样的二元组形式出现,并且能够在运行的时候创建。
MCAPI的通道可以在端点之间被动态创建,然而,通道类型和方向不能被改变除非删除重新创建通道,并且它不支持多播和广播。通道在初始化过程中通常只设置一次。MCAPI运行库执行类似查找路由或者在特定的一对终端节点分配内存的操作。这样,通道直接发送和接收过程都减少了相关开销。
我们使用静态端点名称和通道定义已明确地嵌入在源代码的拓扑。这也使得能够使用外部的工具来自动生成拓扑方便进行初始化。
图二
例如使用三种通信方式的四个节点,终端节点必须有相同的类型,因为一共有六个终端节点。
B 通信方式
1. Message——面向无连接的数据流
2.Packet channels——面向连接的单向FIFO数据流
3.Scalar channels——面向连接的单向特定字节数的FIFO数据流
MCAPI Message 方式进行通行传输端点之间的数据时,无需先建立连接。发送端和接收端的缓冲器必须由用户应用程序提供。MCAPI Message可以与不同的优先级的发送。优先级最高的通信是在图2中展示的消息传递。
MCAPI Packet 通信方式是要求在终端节点在传输数据之前首先建立一个连接,从而就潜在的去除了消息头中有关路由信息的开销(图2中深颜色所标记的地方)。Packet通过单向的FIFO方式来传递数据,通信过程中需要的缓冲由接收端通过MCAPI的实现和发送端用户程序来提供,如图二中间部分描述。
MCAPI scalar 通信方式在终端节点首先建立连接之后传输8-bit 16-bit 32-bit和64-bit 固定大小的数据,就像Packet方式一样,scalar也是通过单向的FIFO的方式来传递数据。
每种通信方式都有自己的API调用,总数大概是50。大约有四分之一是用于通信,通道API调用都设计得简单而且是静态类型,这样最大限度地降低了动态软件结构的开销,这允许应用程序用最低性能最好的延迟访问底层多核硬件。
消息是最灵活的形式,当发送者和接收者是动态变化并且通信不平凡的时候这很有用。这些通常用于同步和初始化。
Packet和Scalar方式提供了发送方和接收方轻量级的类似于socket静态通信机制,在多核中这些通信API保证了类似于ASIC的低开销FIFO通信能力。
第四部分硬件平台的案例研究
图3显示了该研究中使用的片上多核平台。该平台包括两个处理单元(PE),HIBI网络和包含DMA接口的IP块(HIBI PE DMA)及外部存储(HIBI MEM DMA)。处理器有本地的,私人的指令和数据存储器,以及处理器间通信使用消息传递来实现。
该架构是在一块FPGA开发板通过PCIe总线连接到PC或者嵌入式CPU,该平台被合成为Altera的Arria II GX开发板,通信频率能达到100MHz
A、总线接线
块由该取复制以加快通信,并将其与计算重叠数据向/从网络和本地双存储器的护理的DMA连接到总线。
图3
案例研究PC与MPSoC的架构图
DMA由HIBI端的远程主机(Nios 或者PC)配置,这个配置需要4个参数:源地址,目标地址,数量和命令。处理器的DMA可以有一个正在进行的发送网络,但是可以等待来自多个网络的接收数据流。PE为任一接收完成时的中断或者它可以主动轮询接收信道的状态。传输时发送/接收本地片上双端口数据存储器是由程序员显示控制。这里,这些暂存器在处理器上以相同的频率运行。同样,类似于在Cell处理器上SPE存储器,比如PE之间不能互相访问对方的本地存储空间。相反,每个HIBI包装有一组目标地址和PE DMA 进行本地内存和HIBI地址之间地址转换。
内存DMA提供了多种传输通道,都是全双工的。内存可以透明的访问,但是DMA控制器只允许在传输中采用单总线地址。例如,使用DMA从存储器读出的较大的一块数据,显然比按字请求数据效率来得高。这对于HIBI复用地址线和数据线以及在NoCs进行包交换是十分有利的。
B.PC
在普通PC(2.4GHz主频,1024MB内存)运行DebianGNU/Linux 5.0.6,用于开发应用程序和进行FPGA综合仿真。这里的主要目的是展示应用程序代码可以容易的在PC或者Nios上运行,因为MCAPI负责处理核间通信可能是它的PCIe,HIBI或者任何其他。因此,在工作站环境开发应用程序,调试起来更为简单。然后,应用程序代码就可以被移植到FPGA上或者分布到PC和FPGA处理器上。
第五部分MCAPI的实现
图3还展示了在我们的平台上从软件层实现了MCAPI,最靠近硬件的部分时先提出eCos操作系统,然后使用一个DMA驱动。在这种研究情况中,我们已经排除操作系统的影响,我们根据我们的项目”Funbase” (function-based platform)来命名我们实现MCAPI实现:FUNCAPI。
A.分层方法
FUNCAPI的实现分为两个层次:顶层和传输层。顶层实现MCAPI为用户应用程序指定终端节点抽象并且对函数调用只做简单的错误校验。
传输层实现了在这种情况下被称作DMA接口的顶层和HAL层(硬件抽象层)之间的接口。HAL层抽象了底层通信媒体和协议。在这个案例研究中,我们使用FPGA内部HIBI网络和FPGA和PC之间的PCIe。另外的职责就是处理MCAPI数据库发送/接收数据和消息从/去其他物理PE。它把所有用到的终端节点的标识符转换为目标PE的HIBI地址。传输层还具有错误校验的功能,例如检查非法的终端节点访问和长时间没有数据交换的连接。应用程序不能访问不存在的节点或者终端节点,这在应用程序的开发过程中是一个安全的观点。
B.使用虚拟节点的固定功能单元
我们实现了一个创新观点就是:硬件加速器也被当做是一个MCAPI的节点。因此,他们可以被常规的MCAPI函数访问,尽管IP块本身不支持原生MCAPI。这是通过在处理器的传输层虚拟化IP块的终端节点抽象做到的。因此,MCAPI还充当软件/硬件接口和节点,并不用知道它正在与哪一种类型的PE进行通信。这样做主要的好处是,它对应用程序进行逐步加速,包括越来越多的硬线加速器。
下面一个简单的伪代码示例将演示如何为离散余弦变换(DCT)的硬件处理快来虚拟化节点。在设计时IP块将被赋予一个独特的节点数字,在本例中为1。默认MCAPI msg_send()函数将调用DMA控制器驱动(一个C宏 HPD_send ),但是对于这个编号1的虚拟节点来说,它又将执行过程转发到了一个DCT 驱动。最终将会调用HPD_SEND函数,也许是多次,来配置DCT和发送将被进行转换的原始数据。在其他的加速器上很容易重复上述相同的过程。
send_msg(…){
…
switch(node_id){
case ‘1’:
…
dct_drv(…);
…
default:
…
HPD_SEND(…);
…
}
}
C.函数接口
面向无连接的Message通信方式和面向连接的Packet Channel 方式的接口函数都有阻塞和非阻塞的两种变体,例如函数 mcapi_msg_recv()被调用时,会阻塞直到应用程序节点收到信息数据。对于非阻塞形式函数变体,他们的函数名将以”_i”结尾。
本文研究所用到最重要的11个MCAPI接口函数在表1中详细列出,他们主要被分为3个种类:
l 函数1-5是系统的初始化作用,他们只在应用程序的最开始进行调用。
l 函数6-9是MCAPI在不同的通信方式下进行MCAPI节点间发送/接收数据的接口函数。
l 函数10-11 是状态查询函数,例如查询非阻塞函数的状态。
注:所有的API都可以在MCAPI的手册中找到。
就像终端节点和通道,需要的缓冲在编译的时候就静态的保留了,来提升整个系统的可靠性,也方便调试。应用程序必须考虑数据对齐,字节序和消息的总体内部结构。
D.实例
在图4中描述一个顺序执行的实例,它主要完成了初始化和传输单一消息的功能。最左边的4条线描述了软件的生命周期,即应用程序,分别是MCAPI的两层,和DMA驱动。在右边是一个HW网络,简便起见接收端的PE就没有表示出来了。
在实际传递消息之前,必须初始化节点(node)和终端节点(endpoint)。第一阶段,发送方以一个独特的二元组<node_id,port_id>进行初始化来规定发送方的终端节点。相似的,接收方也要执行相同的操作。
在第五阶段,用户应用程序获得一个句柄用来从MCAPI数据库中获得终端节点(endpoint)并且用它来发送数据。这个过程在完全静态的系统中被摒弃,然而,他确保了目标端点的有效性和保留了代码的可移植性,这有利于动态的配置系统。
阶段1-6在整个应用程序的启动过程中只被执行一次,注意,没有数据在初始化的过程中被发送,这简化了API在很多没有共享内存的系统中可以发送数据。应当指出的是,当节点逻辑是静态的时候,这是完全有可能的。在一般情况下,节点也可以被当做一个线程一样动态的创建,并且这个初始化过程在真正线程初始化和MCAPI的具体实现之间就被执行了。
初始化完成之后,消息数据就将使用HIBI_PE_DMA驱动来发送到整个通信网络,FUNCAPI 顶层转发消息到传输层,这就实现了MCAPI终端节点抽象到HIBI地址空间的映射。例如,发送数据到终端节点<node=3,port=1>将转换为目标地址0xF000_0000,一旦HIBI PE DMA配置完成,MCAPI的调用就返回了。
很明显,考虑到通信性能,传输过程调用的API要比初始化过程调用的API更为重要,因此实现MCAPI的重点就在传输层API。
函数 |
含义 |
initialize() |
初始化操作 |
create_endpoint() |
在本地数据库创建endpoint |
connect_pktchan_i() |
在收/发端建立连接通道 |
open_pktchan_recv_i() |
创建接收通道,它确保了收发双方建立通道连接和数据同步。 |
open_pktchan_send_i() |
类似上述操作 |
msg_send() |
发送面向无连接的消息 |
msg_recv() |
接收无连接的消息,将会阻塞直到收到所有数据 |
pktchan_send() |
发送面向连接的数据 |
pktchan_recv() |
接收面向连接的数据 |
test() |
测试非阻塞的函数操作是否执行完成 |
wait() |
等待超时操作,直到非阻塞调用返回 |
表1最必不可少的MCAPI接口和他们的含义
第六部分实现
我们几乎实现所有的MCAPI接口,除了某些测试无阻塞的传输的函数。如上述提到的,节点,终端节点和通道的配置都是静态的。在FUNCAPI传输层关于Nios目前的C代码一共有1500行,底层DMA驱动代码266行,都不包括注释。MCAPI传输层在PC上的实现有1450行,在PCIe驱动上的实现由248行,都是用C写的。这能对MCAPI本身的实现的可移植性、复杂性,有一个大概的评估吧。
必须指出的是,尽管传输层是针对每个不同平台,但是大部分都是可复用的,例如在我们的例子中,95%的代码都十分类似,不管它们位于什么平台,没有操作系统的Nios或者是跑Linux的PC端。后者使用PCIe进行通信,在本文研究中,在linux中被当做驱动访问的功能,在用户空间中被实现。表2 展示了在Nios实现的主要软件组件,在PC端也有相似的集合。
在图2中我们展示了从一个处理器到另一个处理器重新映射一个MCAPI节点,首先图中左边部分(0和1节点)是Nios的实现,第二步,我们对节点1做了从Nios到PC的重新映射,下面的例子是mcapi_mapping.h中的代码段,它显示了地址定义,这是移植到目标处理器上时重新编译之前所需要做的唯一修改。
address_map(Nios_0_addr,pc_addr);
图4 MCAPI执行的Funbase时序图示例
因此,从其他处理器的另一重映射节点在本例中只需要改变一行。如果没有标准化的API,开发人员必须学习基本的通信介质驱动器的使用和重写应用程序代码。MCAPI甚至能够保证在几个小时内做到代码重用,移植到不同的处理器。
代码 |
内容 |
app_x.c |
测试程序 |
mcapi.c |
MCAPI顶层实现 |
funapi_transport_Nios.c |
MCAPI传输层实现 |
mcapi_config.h |
定义常量,例如包大小 |
mcapi_mapping.h |
定义终端节点和映射的物理地址 |
mcapi_datatypes.h |
定义MCAPI数据类型 |
hibi_pe_dma_driver.c |
DMA控制器的硬件抽象 |
hdp_regs_and_macros.h |
底层寄存器和宏定义 |
第七部分性能测量
我们测量的部分包括:内存占用,通信延迟和吞吐量。延迟统计的数据在表3和表4中展示,对于不同的固定大小的数据量,每次测量都重复100次以保证结果的可靠性。测量被分为两个部分:初始化过程和数据传输过程。
通信延迟的测量方法是在NIOS的两个节点node_0和node_1之间使用MCAPI不同的方式进行通信。在传输测量中,我们假设node_1准备好从PE node_0 接收收据,相反当node_0接收数据时也是一样。因此,我们可以区分不同过程中MCAPI各种通信方式的差异。表3中的第一行(面向无连接消息,21个时钟周期)表示在图4中表示的初始化阶段1~6所用的时间。Packet和Scalar方式的通道是面向连接的通道,由于他们在建立连接时需要进行二次握手,他们在初始化阶段将比message方式花费更多的时间。然而,初始化操作仅仅在应用程序开始阶段执行一次,他们的初始化操作是与最终要发送的消息或者包大小无关的。因此,初始化过程中所造成的延迟在长期的数据流传输中时可以忽略不计的。
实际的数据传输将转化为DMA驱动函数HPD_SEND(),如图4的第9条所示。它初始化DMA传输过程中的参数如:数据大小,数据地址,接收方地址和传输数据的大小。在此之后,HIBI_PE_DMA将自动处理剩余部分的传输。相应的,在接收节点上,HIBI_PE_DMA也做相应的初始化来复制接收到的消息到本地内存的目标地址上。msg_recv()函数仅仅只需轮询的去查看DMA的状态来得知是否数据已经准备好。
Packet方式的数据大小显著影响到得到的吞吐量结果。例如,从Nios到Nios发送16B的包时,吞吐量大概是25MB/s,然而发送1KB的包时,吞吐量达到120 MB/s,但是客观的说没有MCAPI时这个吞吐量会分别提高%8和%2。理论上的最大值是 4B ×100MHz =400MB/s。通过PCIe连接的PC和Nios处理器吞吐量显著较低,只有15MB/s,但这些都是由通用的,简单的PCIe linux 驱动只处理单一的 32/64位传送所引起的。其优化就不是本文讨论的内容了。
通信方式 |
初始化时间(时钟周期) |
Message |
21 |
Packet |
90 |
Scalar |
90 |
表3
Message、Packet和Scalar方式初始化过程中的通信延迟
字(32-bit) |
数据传输时间(时钟周期) |
1 |
63 |
2 |
63 |
4 |
67 |
8 |
71 |
16 |
79 |
32 |
105 |
64 |
127 |
128 |
191 |
表4
不同大小包/消息数据往返传输的延迟
A.内存占用
FUNCAPI的代码库占用内存25KB,顶层占用了7KB,传输层占用了18KB。HIBI_PE_DMA驱动库在每片只在系统内存上消耗仅仅1KB。
总的数据内存占用取决于所使用的最大分组/消息大小。当数据量大小为2KB时,内存缓冲的使用率用公式channel_count×max_packet_size。通道数和节点数表示的概念完全不同,例如,在图2中,系统的channel一共有三种类型,Message,packet和scalar。
因此,总的内存使用率应该算上message、packet和scalar的缓冲的总和:1×2KB+1×2KB+4B≈4KB,算下来,程序和数据缓冲总的内存占用约为25+1+4 = 30KB
B 与其他的API实现比较
表格5展示了文献中的结果,表中每一列分为不同的功能:使用的API;硬件平台;内存占用;包括操作系统,系统频率;单向通信延迟;使用的传输类型。许多源报告都是以微秒为单位来说明延迟,我们转化他们为时钟周期,这样很轻易能够看出差别。类似的,我们将报告上的往返时间转化为单向传输的延迟。在我们的MCAPI实现中,在两个PE之间往返的时间延迟的时间范围从63到191个时间周期,具体的值取决于传输的数据量大小,因此,单向的最小延迟大约为32个时钟周期。
此处提供三份来自MPI实现的源报告。Saldana等人的报告表明了零长度的消息传输一共有340个时钟周期的通信延迟。Minhass等人,显然测量的数据量更大,最小的数据传输都有最少1150个时钟周期的延迟,因此他们认为这是系统的瓶颈。另一方面,Mahr等人的实现得出的结果甚至更大,传输128B的数据包有至少9000个时钟延迟。
MPI和OpenMP的开销也被Hung等人做个证明。他们使用MSGAPI得出了这样的结论,当进行最小数据传输传输时,得到了至少1100个时钟周期延迟。因此,MSG方式在特定平台要比传统的CELL SDK通信方式更快,但是在通信延迟上相比较于内存映射I/O慢两倍。StepNP表现出来在消息传递上的性能——小于40个时钟周期。在网络处理过程中,快速通信绝对是十分必要的,因为在这个过程中,任务通常十分小,甚至不到500个指令。综上所述,相较于上述提到的实现方式,我们的实现MCAPI的性能表现得相当优异。
正如在表中所看到的,在相关的工作中,API占用的内存相当少。将数据和程序占用的内存进行分类,即使不那么频繁。尽管如此,Saldana等人展示了8.76KB的通信库大小,这是我们实现的三分之一。然而,Saldana等人,并没有完全的说明,在他们的功能子集中,哪一部分的MPI是支持上述结论的。Mahr等人的实现可以在16KB甚至更小的内存占用中实现MPI,但这些取决于具体配置。作为比较,在NIOS处理器中使用eCos库的内存占用大约是53Kb,这个结论来自于我们较早的原型。在加速器单元中,消息传递和对象请求代理需要逻辑上27kilogates和每个系统12.5KB的内存占用,加起来就是3kilogates/PE和0.5KB/PE。
C.性能考虑
有利于API性能的因素来源于底层硬件和软件层,并且在这些API中做什么操作也会影响到API的性能。缓冲区的管理在此处由应用程序本身完成,所以在测量中将这项指标排除在外。例如,提出IPC机制的Setala等人,不得不因为片上存储大小的限制而使用内存拷贝来接收或者发送数据。除了操作系统页面的上下文切换,这造成的开销引起了严重的传输延迟(至少5个时钟周期每字节)。
与很多API实现相比,我们的MCAPI实现可能会有一些限制,这些可能会造成性能上的差异。首先,所有的节点,终端节点,通道在它们设计的时候就已经被确定了。其次,相较于MPI有超过200个的函数接口,MCAPI只有仅仅50多个API,从API的数目上来说,这是两者巨大的不同。最后,缓冲的管理大部分由用户应用程序完成。
我们从表格5注意到,操作系统造成了主要的开销。例如在Cell传输过程中,不论是发送还是接受,期间的速度,运行Linux的PPE要比不运行操作系统的SPE慢得多。通常情况下,在一个嵌入式处理器上操作系统做上下文切换将会花费数百个时钟周期,另一种极端情况下,在StepNP’s 硬件加速器做一次上下文切换只需要一个时钟周期,而做一次调度只需要40个时钟周期。
另外要注意的是,要避免动态内存分配(在我们的平台上这将花费175个时钟周期),和低效率计划的线程创建(例如1.68毫秒,它相当于五百万次循环)。类似的,在虚拟存储系统中需要表后备用缓冲器(TLB),但这在运行时可能会产生显著的开销,例如缺页中断可能会花费500到1500个时钟周期,页面替换将会花费85K-500K的周期更换。
第八部分 结论
我们已经实现,据我们所知,应该是首次把多核协会(Multicore Association)定义的MCAPI应用到一个以FPGA为基础的MPSoC(片上多核系统),这包括了对于硬件IP-块的虚拟终端节点(endpoint)支持。考虑到整个系统的层次结构,我们把平台的传输层专门独立出来,这样可以轻易地把MCAPI移植到没有操作系统的NIOS和运行linux的PC端。可移植性和性能上的评估在这个案例中进行了测试。此外,本文还做了和其他文献中提到的API进行对比。
很明显,当应用程序的并行化随着时间的推移不停的增加时,通用、规范的通信API就更需要提供嵌入式解决方案的支持了。MCAPI正是当前发展窘境的一种解决方案,它看起来是相当有前途的。
我们今后的工作是改善和提升传输层的结构来减少内存占用,并且为MCAPI传输层的实现支持多处理低级别的通信介质驱动。另外我们还需要研究的内容是:彻底调查研究清楚API的易用性和开销来总结API之间的差异。
作者 |
API |
平台 |
MEM占用 |
OS |
f[MHz] |
延迟[us] |
延迟[时钟周期] |
传输类型 |
Saldana |
MPI |
MicroBlaze |
8.7KB |
No |
40 |
8.5 |
340 |
TMD-MPI |
Minhass |
MPI |
NIOS |
10KB |
No |
59 |
23 |
1150 |
Packet |
Mahr |
MPI |
MicroBlaze |
11.5-16KB |
No |
100 |
- |
9000 |
MPI 128字节 |
Hung |
CellSDK MSG MSG MSG MSG |
CELLBE |
总数小于256KB |
Yes No Yes No Yes |
3200 |
2.96 ~0.35 ~1.5 ~0.4 ~1.8 |
9469 ~1100 ~4800 ~1300 ~5800 |
mailboxPPE->SPE 16B SPE->SPE 16B PPE->SPE 2KB SPE->SPE 2KB PPE->SPE |
Kunjush |
CellSDK |
CELLBE |
N/A |
No |
3200 |
0.07 |
220 |
16B put/get SPE->SPE |
Abellan |
CellSDK |
CELLBE |
N/A |
Yes Yes No No Yes |
3200 |
0.18 3 ~0.15 ~0.25 16800 |
512 9600 ~500 ~800 ~5.4m |
mailboxPPE->SPE maiboxPPE->SPE 16BSPEDMA 2KBSPEDMA ThreadPPE |
Paulin |
DSOC |
StepNP |
12.5KB+n*0.5KB |
No |
200 |
<0.2 |
<40 |
MessagePassing |
Matilai |
MCAPI |
NIOS,PC |
24.8KB,4KB |
No |
100 |
- |
32 |
Message4字节 |