一、名词解释
RDMA(Remote Direct Memory Access):远程直接内存访问
MTT(Memory Translation Table):内存翻译表
MPT(Memory Protection Table):内存保护表
LKEY(Local Key):本端密钥
RKEY(Remote Key):远端密钥
二、背景技术
RDMA使能硬件直接访问用户态应用软件分配的内存从而实现零拷贝和绕过内核以达到低延迟和高带宽。为了达到此目的,通信前,应用软件必须向驱动软件注册内存,提供内存的起始虚拟地址、长度和访问权限(比如读、写)等信息。驱动软件根据虚拟地址和长度,会构建内存翻译表(MTT),每一个MTT表项对应注册内存的一个物理页起始地址,MTT的大小就是注册内存的物理页个数。驱动软件进一步向硬件注册内存。硬件会为注册内存构建内存保护表(MPT),MPT包含内存的起始虚拟地址、长度、访问权限和MTT地址等信息,并返回本端密钥(LKEY)和远端密钥(RKEY)给应用软件。LKEY/RKEY可以被硬件用来索引MPT。
通信时,应用软件如果要发送或者接收数据,可将发送或者接收内存的虚拟地址、长度和LKEY告诉硬件,硬件会根据LKEY找到MPT,权限检查通过后,硬件根据MTT翻译虚拟地址成物理地址,从而读写发送或者接收内存的数据。应用软件如果要读写远端内存,可以将远端内存的虚拟地址、长度和RKEY提供给硬件,硬件会将其嵌入发送报文中,远端的RDMA硬件收到报文后根据RKEY找到MPT,权限检查通过后,根据MTT翻译虚拟地址成物理地址,从而读写目的内存的数据。
MTT表以页为单位翻译地址,每个MTT表项(8B)表示一个物理页的起始地址。比如注册2GB内存,页长是4KB,则需要512K个MTT表项,即MTT的大小是512K。MTT通常以页表的方式实现,一页4KB最多容纳512个MTT表项,当MTT大小大于512时则是多级页表。
如上图所示MTT的大小是513时MTT为二级页表,一级页表的每一个表项表示的是二级页表的物理地址,而二级页表的表项才是注册内存的物理页起始地址。这个时候我们看到硬件需要多一次查找才能找到目标MTT表项,并且每次找满512个MTT表项后就得重新查找。在内存的使用方面,多了一个中间页表(即一级页表)而最后一个终端页表(即二级页表)也没有用满,造成浪费。MTT大小和页表级数、中间页表个数的关系如下:
MTT大小 |
页表级数 |
中间页表 |
1 |
0 |
0 |
2到512 |
1 |
0 |
513到256K |
2 |
1 |
256K+1到128M |
3 |
2-513 |
自研RDMA建立一个物理连续的MTT内存池的概念,管理MTT的分配和回收,确保MTT的物理地址连续。从而解决上述的查找效率和内存浪费的问题。
三、实现方法
本系统主要包括:
- MTT内存池初始化模块
- MTT内存分配模块
- MTT内存回收模块
系统分析流程包括:
- 当驱动软件加载时,MTT内存池初始化模块启动初始化流程:
- 预留一段物理连续的内存,作为一个大空闲块链入空闲列表。链入的方法可以是利用空闲块的一小部分记录空闲块的元数据,例如空闲块的起始地址、长度和下一个空闲块的地址等。
- 当应用软件注册内存时,驱动软件构建MTT,MTT内存分配模块触发分配流程:
- 从空闲链表查询一个不小于MTT大小的空闲块,
- 如果此空闲块都分配给MTT,则链出此空闲块
- 否则修改空闲块的元数据
- 当应用软件撤销内存时,驱动软件释放MTT,MTT内存回收模块触发回收流程:
- 将MTT按照地址顺序链入空闲列表
- 如果与前或后空闲块物理地址相邻,则向前或后合并
- 从空闲链表查询一个不小于MTT大小的空闲块,
如下图是包含初始化、分配和回收的一个例子:
- 初始化后整块内存(除了元信息)加入空闲列表,列表中只有一个空闲块。
- 依次有两次内存注册,则MTT1和MTT2从空闲块分配出去,空闲块的addr和len指向实际的地址和长度。
- MTT1所代表的内存被注销,MTT1的内存被链入空闲列表,空闲列表有两个空闲块。
- MTT2所代表的内存被注销,MTT2的内存被链入空闲列表,MTT2的内存可以和前后的空闲块合并,合并后,空闲列表又只有一个空闲块。