百度EdgeBoard如何实现嵌入式AI解决方案的内存驱动设计

发布时间:2021-08-30 阅读量:823 来源: 我爱方案网 作者: 我爱方案网整理

1.背景介绍


由于FPGA具备可编程和高性能计算的特点,基于FPGA硬件的AI计算加速,正广泛地应用到计算机视觉处理领域。其中极具代表性的部署方式之一就是使用FPGA和CPU组合构成异构计算系统,并在CPU上搭载Linux操作系统,运行AI推理引擎框架及视频图片处理等各种业务。其中,如何协调CPU和FPGA的计算关系,成为这套异构系统的关键,而这部分关键技术则是由驱动系统来完成的。


协调CPU和FPGA这对异构兄弟的计算关系,可以有许多模式,根据不同的应用场景会有很大的变化。一般在端侧,整个系统的应用比较单一可控,较少考虑并发及虚拟的情形。根据这一情况,EdgeBoard应运而生。


2.EdgeBoard介绍


EdgeBoard是百度打造的基于FPGA的嵌入式AI解决方案及基于此方案实现的系列硬件。作为端侧的解决方案,没有在PL侧为FPGA设计专用的内存,而是采用了PS和PL侧共用DDR内存的结构。因此,对这种异构系统的CPU和FPGA的协调就落在了内存的管理方面,这就是驱动系统中关于内存管理的子系统。


3.全文概述


本文将重点介绍EdgeBoard中关于CPU和FPGA内存驱动设计的关键技术。下图是整体EdgeBoard的软件框架图,其中内存驱动位于内核部分。下面将从内存的分配、释放、回收等方面来逐步介绍。


10.png


4.内存的特点和FPGA的内存需求


在FPGA芯片PS侧,CPU使用多级缓存来访问DDR,在Linux操作系统中,使用内存映射页面(通过页表来管理),而对DDR的物理连续性没有要求,它们被映射到虚拟连续的地址空间中。而在PL侧的FPGA一般未使用任何缓存机制,它们在计算中都是直接访问DDR。每一次读写操作都是读或写一个连续的内存空间,而且要求这片内存的起始地址要对齐在一个特定的地址偏移处(偏移0x10)。一次计算中的多次读写都要求访问的DDR是一致连续的。


针对CPU和FPGA这样的内存需求,我们设计Linux驱动内存的子系统时,就要充分考虑到:1)cache的影响;2)FPGA使用内存的物理连续性;3)传递给FPGA使用的内存块要满足偏移要求(segmentalignments)。


5.保留系统内存


针对上述需求,我们采用分隔物理内存的设计方案,从整体系统中保留其中的一部分内存,让Linux只使用另一部分内存。这部分被保留的内存,分配权归内存驱动,驱动从保留部分中分配的内存块在Linux系统中和FPGA系统中都可以访问。在此期间,分配时要保证物理连续和起始偏移特性,使其能满足FPGA的需求。


在EdgeBoard实践中,我们采用的是Xilinx的ZynqMP系列的FPGA芯片,使用PetaLinux工具链来编译Linux内核,并采用DeviceTree中的reserved-memory节点来实现内存的保留。例如,系统总体2GB内存,保留1GB给FPGA,留下1GB给Linux操作系统,DeviceTree中相关节点的设定就是这样的:


11.png


下面就从驱动设计实现的各个方面介绍。


6.初始化内存的内部映射


FPGA总体设备驱动是采用字符设备platformdriver的形式来编写的:在Device的probe阶段,对驱动内所保留的内存块做好内存映射(memremap),并使用合理的数据结构,保存好各个参数,以供后续使用。例如:


12.png


mem_start、mem_end、base_addr等结构成员的定义如下:


13.png


7.内存的分配


关于内存的分配,采用了mmap调用的方式:在FPGA设备的初始化期间,初始化字符设备时传递了file_operations结构变量,这个结构变量的mmap指针初始化为我们的内存分配函数。


内存分配中,我们使用了内核提供的bitmap数据结构,来管理我们保留的内存区域——bitmap位数组中的每一位代表着16k的一个内存块,另外还使用相同长度的数组来管理内存被分配的客户owner(即file指针)、内存分配的块的数量等信息。


另外,在分配的内存对应的vma(VMMMemoryArea)中,我们还注册了自己的私有数据privatedata来记录对应内存的必要信息:如对应内存块的总线物理地址范围和映射地址、bitmap位数组的索引等,用于地址转换;再如对应内存块的一些finger信息,用来标识保留内存块。


同时,我们也为VMA的vm_ops注册了close函数,用于为对该块内存的回收做好准备。


关于内存分配的代码量较大,这里就不一一列举了。


8.内存的回收


已分配出去的内存块都需要回收,其中有两种最具代表性的情况,一种是用户release一块内存的处理,另一种则是用户关闭设备时对未release的内存块的清理回收。


当用户release一个内存块时,对应的vma的close函数会被自动执行。为此,我们注册这个函数作为内存释放处理函数:函数实现中,首先检测privatedata避免错误处理,然后恢复对应的bitmap位数组中的位信息,清理owner和块数量信息,使得这块保留内存又回到了待分配的状态。


当用户关闭设备时,会调用设备注册的release函数。因此,在设备的release函数中,我们遍历owner数组来清理owner与设备的file指针相同的内存块,以此达到批量回收的目的。


9.内存的地址转换


内存的地址转换,是完成总线物理地址和虚拟逻辑地址的双向转换,为内存cache的flush/invalidate、以及交由FPGA之时要进行的处理等提供支撑。系统也通过两个IOCTL向用户层暴露这两个转换操作。


地址转换操作中,首先找到对应的vma,然后计算出offset,最后检查vma对应的标识是不是保留的内存块——如果是,就使用我们vma保存的private_data中的信息及offset完成相关的计算。


10.内存缓存的flush和invalidate操作


在CPU及其异构兄弟FPGA之间,使用DDR内存来传送数据时,需要使用flush或invalidate来消除对应缓存的影响。


首先,我们的驱动代码是运行在CPU上面的,当针对一片内存的处理从CPU转移到FPGA之前,需要对这片内存的cache执行flush操作,使得内存cache中的所有改动都写入到DDR,然后FPGA开始对它的处理工作。其次,当针对一片内存的处理从FPGA转移到CPU之前,需要对这片内存的cache执行invalidate操作,使得cache内容无效,下次CPU直接读取即从DDR中去主动load从而刷新cache。这样,CPU就可以很好地跟FPGA相处了。


对于flush和invalidate操作,则是CPU体系相关的。EdgeBoard使用的是A53v8(对应于AArch64执行集),cacheflush和invalidate的代码如下:


14.png


11.内存驱动中其它功能设计及考虑


上文中提到的保留内存区域中每个保留内存块的大小是16K,其实这里是可以启用多规格的,这样用户在使用上就会更加方便,用途也会更多。但是关于内存管理部分就需要更多的数据来进行管理了。


另外,我们可以通过建立一些IOCTL的方式为不同进程之间的内存共享做出一些快速、简洁的方案,这也是我们可以在内存驱动中设计考虑的。


相关资讯
核心对比!无源晶振与有源晶振在结构和工作原理的本质区别

无源晶振与有源晶振是电子系统中两种根本性的时钟元件,其核心区别在于是否内置振荡电路。晶振结构上的本质差异,直接决定了两者在应用场景、设计复杂度和成本上的不同。

温度稳定性对RTC晶振的计时误差影响与分析

RTC(实时时钟)电路广泛采用音叉型32.768kHz晶振作为时基源,但其频率稳定性对温度变化极为敏感。温度偏离常温基准(通常为25℃)时,频率会产生显著漂移,且偏离越远漂移越大。

从参数到实践!剖析有源晶振的频率稳定度、老化率及正确接线方案

有源晶振作为晶振的核心类别,凭借其内部集成振荡电路的独特设计,无需依赖外部电路即可独立工作,在电子设备中扮演着关键角色。本文将系统解析有源晶振的核心参数、电路设计及引脚接法,重点阐述其频率稳定度、老化率等关键指标,并结合实际电路图与引脚定义,帮助大家全面掌握有源晶振的应用要点,避免因接线错误导致器件失效。

如何对抗晶振老化?深入生产工艺与终端应用的防老化指南

晶振老化是影响其长期频率稳定性的核心因素,主要表现为输出频率随时间的缓慢漂移。无论是晶体谐振器还是晶体振荡器,在生产过程中均需经过针对性的防老化处理,但二者的工艺路径与耗时存在显著差异。

无源晶振YSX321SL应用于高精度HUD平视显示系统YXC3225

在现代汽车行业中,HUD平视显示系统正日益成为驾驶员的得力助手,为驾驶员提供实时导航、车辆信息和警示等功能,使驾驶更加安全和便捷。在HUD平视显示系统中,高精度的晶振是确保系统稳定运行的关键要素。YSX321SL是一款优质的3225无源晶振,拥有多项卓越特性,使其成为HUD平视显示系统的首选。