CXL1.0/1.1 引入了 CXL Type3 设备,可以实现单主机动态内存拓展需求,但仅限于单主机范围内. CXL2.0 引入了 CXL SWITCH,通过 CXL SWITCH 可以将多个设备(如 CPU、GPU 和加速器)连接在一起,使它们能够共享资源. 另外 CXL SWITCH 允许系统根据需要添加更多设备,支持更大的系统规模,通过动态管理资源,系统可以轻松适应不断变化的工作负载. 最后 CXL SWITCH 使得多个主机能够同时访问同一资源,支持更复杂的多主机环境,这对于需要高性能计算和数据共享的应用特别重要. 以上特点为 CXL 实现资源池化奠定了基础, 为了实现资源池化,CXL Type3 设备的结构也进行拓展,接下来本文将描述 Type3 设备在资源池化了变化.
SLD(Single Logical Device) 设备是 CXL2.0 引入的一个概念,其针对 CXL Type3 设备的连接方式进行划分,SLD 设备在某一时刻只能连接到一个主机上,具有可被 CXL.io 识别的 Logical ID,其具有如下特点:
- 单一逻辑设备: SLD 设备在每个连接的主机中表现为一个单一的逻辑设备,意味着它的资源和功能对主机而言是统一和一致的
- 与主机的连接: SLD 设备通常通过一个 CXL 端口与主机直接连接,可以提供高带宽和低延迟的数据传输
- 内存共享: SLD 设备能够支持共享内存的功能,使得多个主机能够高效地访问相同的内存区域, 这对于需要频繁数据交换和共享资源的应用场景尤为重要
- 管理和控制: SLD 设备能够支持来自 Fabric Manager(FM)的管理和控制,方便系统在运行时进行动态配置和资源管理
通俗来讲 SLD 只能以一个独立的 CXL Type3 设备向多主机展示,多主机可以通过分时共享的方式将 SLD 绑定到自己的 VH 里,也就是说如果某主机 VH 的 vPPB 绑定了一个 SLD 设备,那么其他主机 VH 的 vPPB 同一时刻不能在绑定该 SLD. 因此 SLD 可以提供更好的资源隔离, 另外 SLD 可以将 Type3 设备 1:1 映射到被绑定的 VH 里. 虽然 SLD 可以实现资源池化和共享,但一个 CXL Type3 设备只能被一个主机使用,其并不能更高效的利用 CXL Type3 设备上的资源, 这些资源包括 CXL 的高带宽和灵活的容量.
MLD(Multi-Logical Device)是一种支持多个逻辑设备的 CXL 架构特性, 其可以将单一的 CXL Type3 物理设备虚拟成多个逻辑设备,每个逻辑设备暴露给主机是一个独立的 CXL Type3 设备,MLD 具有一下特点:
- 多个逻辑设备: CXL MLD 允许在单个物理设备上暴露多个逻辑设备, 每个逻辑设备可以被视为独立的设备,具有自己的 ID 和资源
- 共享资源: 通过 MLD,多个主机可以共享同一个物理设备的资源, 这种特性对于提升内存和计算资源的利用率非常重要
- 增强可扩展性: MLD 的引入提高了系统的可扩展性,使得多个主机可以通过 CXL 互联,能够同时访问和利用物理设备的资源
- 灵活的资源管理: CXL MLD 支持动态的资源分配和管理,使得系统能够根据需求动态调整资源配置
通俗来讲 MLD 就是将一个物理的 CXL Type3 设备虚拟成多个独立的 CXL Type3 设备,这样可以更细粒度的进行资源隔离和共享,这样可以充分利用 CXL 的高带宽,同时由增加了 CXL 池化的利用率,主机可以更合理独占一个 CXL Type3 设备.
MLD 不仅可以将一个物理设备虚拟成多个逻辑设备,也可以将多个物理设备的逻辑设备合成一个 CXL Type3 设备,换句话说就是在支持 MLD 的场景,一个 CXL Type3 设备可以有多个物理设备的切片构成,这样做的好处是可以大大提高 CXL Type3 设备的带宽,通过一定的交织(Interleaving) 技术,可以实现多条内存指令并行访问多个 CXL 物理设备.
MLD 设备由 Fabric Manager(FM) 负责管理,FM 可以通过静态或动态方式将 MLD 设备绑定到不同主机 VH 的 vPPB 上. 例如在主机初始化之前,FM 先将 MLD 绑定(Bind)到指定主机 VH 的 vPPB 上,然后主机上电初始化就可以发现该 CXL Type3 设备. FM 也可以在主机运行过程中,通过热插(Hotplug)方式将一个 MLD 动态绑定到指定主机 VH 的 vPPB 上,同理也可以通过热拔(Hotremove)方式将一个 MLD 动态从指定主机 VH 的 vPPB 上解绑(Unbind).
MLD Practice
BiscuitOS 提供了 MLD 的实践环境,其 CXL 拓扑如上图, BiscuitOS 使用两个虚拟机作为两个服务器主机,并使用 QEMU 的 QMP 充当 Fabric Manager(FM). 在初始状态下,CXL Type3 物理设备作为 MLD 设备虚拟暴露出两个逻辑设备,两个逻辑设备并未绑定到任何主机的 VH 上. 在两个主机上电之后,FM 可以根据需求将 MLD 绑定到指定 VH 的 vPPB 上,也可以从指定 VH 的 vPPB 上进行解绑. 接下来在 BiscuitOS 上进行实践, 请参考如下命令:
# 切换到 BiscuitOS 项目目录
cd BiscuitOS
# 选择开发环境,如果已经选择过可以跳过,这里与 linux 6.10 X86 为例
make linux-6.10-x86_64_defconfig
# 通过 Kbuild 选择需要部署的应用程序
make menuconfig
[*] DIY BiscuitOS/Broiler Hardware --->
[*] CXL: Compute Express Link
CXL Hardware Topology (CXL2.0: x2 Host(VH) + MLD) --->
[*] Package --->
[*] HETEROGENEOUS MEMORY MANAGEMENT
[*] CXL MLD: Multi Logical Device --->
# 配置完毕保存,然后进行部署
make
# 切换到实践案例所在目录
cd output/linux-6.10-x86_64/package/BiscuitOS-CXL-MLD-default
# 准备依赖工具
make prepare
# 编译实践案例
make download
make build
当第一个主机启动之后,使用 cxl 命令查看 CXL 拓扑结构,可以看到没有任何的 CXL Type3 设备被识别到,接着使用 lspci 命令查看 PCIe 总线,可以看到 CXL SWITCH(BDF 0E:00.0) 之下没有绑定任何 CXL Endpointer 设备. 接下来新启动一个终端来启动第二个主机,参考如下命令:
# 切换到 BiscuitOS 项目目录, 同理以 linux 6.10 X86 为例
cd BiscuitOS/output/linux-6.10-x86_64
# 直接启动第二个主机
./RunBiscuitOS-CXL.sh
当第二个主机启动之后,使用 cxl 命令查看 CXL 拓扑结构,可以看到没有任何的 CXL Type3 设备被识别到,接着使用 lspci 命令查看 PCIe 总线,可以看到 CXL SWITCH(BDF 0E:00.0) 之下没有绑定任何 CXL Endpointer 设备. 此时两个主机已经环境已经部署完毕,两个主机 VH 的 vPPB 并没有绑定任何 MLD, 接下来使用 FM 进行 MLD 绑定. 首先选择第一个主机的终端,使用如下命令:
# 1. 按下快捷键进入 FM 模式: [Ctrl-A C]
# 2. 绑定 SLD
object_add memory-backend-file,id=CXL-MLD0,mem-path=/tmp/CXL-MLD0,share=on,size=256M,align=16M,offset=0
object_add memory-backend-file,id=CXL-MLD1,mem-path=/tmp/CXL-MLD0,share=on,size=256M,align=16M,offset=256M
device_add cxl-type3,bus=CXL-SWITCH0-DP0,volatile-memdev=CXL-MLD0,id=CXL-DDR0
device_add cxl-type3,bus=CXL-SWITCH0-DP1,volatile-memdev=CXL-MLD1,id=CXL-DDR1
# 3. 按下快捷键退出 FM 模式: [Ctrl-A C]
# 4. 重新遍历 PCIe 树
echo 1 > /sys/bus/pci/rescan
执行完上面的命令之后,Fabric Manager 将第一台主机 VH 的 vPPB 绑定到了 MLD 设备上,此时可以看到主机识别两个 CXL Type3 设备,其由 DDR 构成且总容量为 512MiB, 接下来在第一台主机上访问该 CXL Type3 设备.
- cxl create-region -d decoder0.0 -m mem0 -s 512M -t ram -w 1 -g 4096 -u: 命令用于创建一个 CXL Region
- cxl create-region -d decoder0.0 -m mem1 -s 512M -t ram -w 1 -g 4096 -u: 命令用于创建一个 CXL Region
- cxl enable-region region0: 创建完毕之后使用该命令使能 CXL Region
- cxl enable-region region1: 创建完毕之后使用该命令使能 CXL Region
- daxctl reconfigure-device –mode=devdax dax0.0 –force: 将 CXL Type3 设备模式修改为 DEVDAX
- daxctl reconfigure-device –mode=devdax dax1.0 –force: 将 CXL Type3 设备模式修改为 DEVDAX
- BiscuitOS-CXL-SLD-default READ: 从 CXL Type3 设备上读取数据
- BiscuitOS-CXL-SLD-default WRITE <MESSAGE>: 向 CXL Type3 设备写入数据
执行完这些命令之后,可以看到主机一可以正常访问 MLD 映射的 CXL Type3 设备,并向设备写入 “HELLO-BiscuitOS-HOSTA”, 那么接下来让 FM 动态解绑,并将 MLD 动态绑定到主机二 VH 的 vPPB 上, 参考如下命令:
# 0. 主机一按下快捷键进入 FM 模式: [Ctrl-A C]
# 1. FM 解绑 SLD
device_del CXL-DDR0
device_del CXL-DDR1
object_del CXL-SLD0
object_del CXL-SLD1
# 2. 主机二按下快捷键进入 FM 模式: [Ctrl-A C]
# 3. 绑定 SLD
object_add memory-backend-file,id=CXL-MLD0,mem-path=/tmp/CXL-MLD0,share=on,size=256M,align=16M,offset=0
object_add memory-backend-file,id=CXL-MLD1,mem-path=/tmp/CXL-MLD0,share=on,size=256M,align=16M,offset=256M
device_add cxl-type3,bus=CXL-SWITCH0-DP0,volatile-memdev=CXL-MLD0,id=CXL-DDR0
device_add cxl-type3,bus=CXL-SWITCH0-DP1,volatile-memdev=CXL-MLD1,id=CXL-DDR1
# 4. 按下快捷键退出 FM 模式: [Ctrl-A C]
# 5. 重新在第二主机上遍历 PCIe 树
echo 1 > /sys/bus/pci/rescan
执行完上面的命令之后,Fabric Manager 将第二台主机 VH 的 vPPB 绑定到了 MLD 设备上,此时可以看到主机识别两个 CXL Type3 设备,其由 DDR 构成且总容量为 512MiB, 而主机一已经看不到 CXL MLD 设备了. 接下来在第二台主机上访问该 CXL Type3 设备.
- cxl create-region -d decoder0.0 -m mem0 -s 512M -t ram -w 1 -g 4096 -u: 命令用于创建一个 CXL Region
- cxl create-region -d decoder0.0 -m mem1 -s 512M -t ram -w 1 -g 4096 -u: 命令用于创建一个 CXL Region
- cxl enable-region region0: 创建完毕之后使用该命令使能 CXL Region
- cxl enable-region region1: 创建完毕之后使用该命令使能 CXL Region
- daxctl reconfigure-device –mode=devdax dax0.0 –force: 将 CXL Type3 设备模式修改为 DEVDAX
- daxctl reconfigure-device –mode=devdax dax1.0 –force: 将 CXL Type3 设备模式修改为 DEVDAX
- BiscuitOS-CXL-SLD-default READ: 从 CXL Type3 设备上读取数据
执行完这些命令之后,可以看到主机二可以正常访问 MLD 映射的 CXL Type3 设备,并直接从 CXL Type3 设备上读到了主机一写入的字符串 “HELLO-BiscuitOS-HOSTA”, 此时可以验证 FM 已经将同一个 MLD 动态绑定到新主机 VH 的 vPPB 上,形成第二个主机的 CXL Type3 设备. 至此实践完毕.