嵌入式AI解决方案EdgeBoard的内存驱动设计

  • 首页 - 资讯 - 娱乐 - 赛事 - 房产 - 汽车 - 财经 - 科技 - 女性 - 本地 - 时政 - 明星 - NBA - 买房行情 - 新车上市 - 投资理财 - 家电 - 整形 - 化妆 - 健康 - 网站地图
您所在位置:主页 > 北京视窗 > 资讯 > 正文

嵌入式AI解决方案EdgeBoard的内存驱动设计

  • 北京视窗 来源:未知 2019-09-30
  • 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的软件框架图,其中内存驱动位于内核部分。下面将从内存的分配、释放、回收等方面来逐步介绍。

     

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

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

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

    5.保留系统内存

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

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

     

     

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

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

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

     

     

    mem_startmem_endbase_addr 等结构成员的定义如下:

     

     
    7.内存的分配

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

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

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

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

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

    8.内存的回收

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

    当用户release一个内存块时,对应的vma的close函数会被自动执行。为此,我们注册这个函数作为内存释放处理函数:函数实现中,首先检测private data避免错误处理,然后恢复对应的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执行集),cache flush和invalidate的代码如下:

     

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

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

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

    12.文末福利

    据可靠小道消息:EdgeBoard正在打折中,历史最低价,降价1000元,有兴趣可以访问“百度AI市场”官网查看https://aim.baidu.com/product/5b8d8817-9141-4cfc-ae58-640e2815dfd4

     

     

     

    分享或转贴至:
  • 关于我们 | 我要投稿 | 网站地图 | 法律声明 | 友情链接 | 返回顶部
    Copyright © 2000-2011 http://www.bj.onhot.cn/ Corporation, All Rights Reserved
    北京视窗版权所有 未经书面授权 不得复制或建立镜像