前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >UEC规范v1.0 - 2.软件层_整体架构_UE与libfabricAPI映射关系详解

UEC规范v1.0 - 2.软件层_整体架构_UE与libfabricAPI映射关系详解

原创
作者头像
晓兵
修改于 2025-06-16 00:15:33
修改于 2025-06-16 00:15:33
21700
代码可运行
举报
文章被收录于专栏:DPUDPU
运行总次数:0
代码可运行

上文: UEC规范v1.0 - 1.简介_整体架构_软硬件分层(https://cloud.tencent.com/developer/article/2530955)

2.2 UE Libfabric 映射

本文档指定了 libfabric v2.0(也称为开放结构接口 (OFI))与超级以太网传输 (UET v1.0) 之间的映射,以及对 UET OFI 提供商的要求。这些映射是启用 UET 上的通信库和服务的重要组成部分,包括对 MPI、*CCL、SHMEM/PGAS 和其他通信用途的支持。UET 必须遵循这些通信库和服务的期望。此外,映射依赖于 UET 语义和配置文件。预计每个 UET 结构端点 (FEP) 供应商都将提供针对其 FEP 优化的 UET libfabric 提供商;但是,本规范定义了实现 UET FEP 之间互操作性的要求。Libfabric 已被选为 UET 的主要网络数据平面 API,因为它是一个灵活的开源框架,被各种用于 AI 和 HPC 工作负载的通信库所使用。Libfabric 已通过规范引用纳入本规范。本规范并非旨在提供 libfabric 的教程描述。libfabric.org 提供了 libfabric 及其 API 的详细信息。如果可能,我们会提供 libfabric 主页的参考资料。请注意,这些参考资料可能会有所变更。总而言之,libfabric 提供了一个专为高性能、并行和分布式应用程序量身定制的通信 API。作为一个低级通信库,它抽象了各种网络技术。然而,在此背景下,我们将其用途定义为 UET,旨在消除歧义,同时增强互操作性并简化调试。Libfabric 已实现大规模部署,其开源生态系统适合随着 UET 的发展而不断改进。Libfabric 支持 LinuxWindowsFreeBSD 和 macOS 平台,并使用 GPLv2/BSD 双许可证或兼容许可证(例如 MIT)。API 的设计充分考虑了可扩展性。Libfabric 是基于被称为“提供程序”的插件概念构建的。 UET 功能的软件组件是供应商提供的 UET 提供商的一部分。libfabric 核心通过通用的提供商 API 与所有提供商通信。libfabric 软件架构如图 2-2 所示。图中所示的应用程序仅供参考,并非详尽无遗。

libfabric API 分为四大类:

• 控制(发现)

o 用于确定可用的通信服务类型

• 通信(连接管理、地址向量)

o 用于在端点之间建立通信

• 完成(事件队列、完成队列、计数器)

o 用于报告数据传输操作结果、连接建立状态、集体加入结果和其他异步事件

• 数据传输(消息、标签匹配、RMA、原子操作、集体操作)

o 用于在端点之间传输数据,支持不同的通信范式

o 图 2-2 所示的四种数据传输范式(消息、标签消息、RMA 和原子操作)针对点对点通信。

集体操作是第五种数据传输范式,旨在在大量对等节点之间进行协调的原子操作。 本规范涵盖了所有这些 API 类别。 libfabric 提供程序通过特定于供应商的底层软件和硬件接口实现 libfabric API。Libfabric 并未定义提供程序用于访问网络硬件的软件/硬件接口。libfabric UET 提供程序软件架构如图 2-3 所示。

必须提供内核驱动程序,以方便执行需要特权实体的操作,例如 JobID 分配、配置或安全密钥管理。出于性能考虑,供应商的低级 NIC 硬件接口在访问硬件时应使用内核旁路技术。内核驱动程序与特权实体之间的接口称为 UET 控制 API。与内核驱动程序交互的特权实体预计会因部署而异。因此,UET 标准化了 Linux 实现的 UET 控制 API,以允许:

• 实现标准接口的内核驱动程序跨部署进行互操作;以及

• 特权实体与来自多个供应商的内核驱动程序进行互操作。

Netlink 因其灵活性、可扩展性和广泛可用性而被选为 Linux 环境中 UET 控制 API 的基础。非 Linux 操作系统的实现预计也将提供类似的功能。本规范的后续章节将提供有关 UET 控制 API 的更多详细信息。

2.2.1 应用用例

不同的应用程序有不同的通信需求。本节重点介绍 UET 考虑的几个应用用例,并对其 libfabric API 的预期使用情况进行了简要概述。其他用例也已考虑,但未在此处记录,例如用于存储或远程过程调用 (RPC) 等目的的各种客户端/服务器应用程序。表 2-3 总结了部分 UET 目标应用的 libfabric API 预期使用情况

2.2.2 UET 配置文件

UET 定义了多个配置文件,以便在实现复杂性/成本和功能之间进行权衡。每个 UET 配置文件对应一组所需的功能。每个配置文件所需功能的详细信息在 SES 规范中定义。三个 UET 配置文件按功能顺序(从少到多)如下:

  1. AI 基础
  2. AI 完整
  3. HPC

Libfabric 通过为应用程序提供广泛的参数集来提供灵活性。这些参数通常包含在 libfabric 结构中。UET 对必须支持的参数集进行了限制。表 2-4 总结了每个配置文件必须支持的参数。未显示的参数具有特定于供应商的值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1. 完全匹配与通配符标签由 fi_tagged() API 的“ignore”参数区分;请参阅第 2.2.5.4.2 节。
2. FI_DIRECTED_RECV/FI_TAGGED_DIECTED_RECV 所需的支持级别仅限于第 2.2.4.3 节中指定的授权要求和第 2.2.5.4.2.1 节中指定的发起方 ID 匹配要求。
3. libfabric 提供程序通过 fi_atomic() API 指示其支持的原子操作;获取原子操作和非获取原子操作是不同的操作;请参阅第 2.2.5.4.4 节。
4. 如果支持可扩展接收队列,则必须为端点分配连续索引,每个接收队列一个索引。连续索引的分配可以使用表 2-7 中描述的服务配置文件完成,也可以通过第 2.2.5.3.5.1 节中描述的配置系统完成。
5. 最大 PDU 是指根据 UE SES 规范中的定义,单帧的最大有效载荷(即 UET 有效载荷)。

Libfabric v2.0 新增了通过 fi_setopt() API 单独设置 RMA 操作最大消息大小的功能。所有配置文件的 UET 要求如下: 1 GB <= UET 最大 RMA 消息大小 <= (4GB - 1) 每个配置文件的完成计数器要求在第 2.2.5.3.7 节中指定。表 2-5 包含表 2-3 中所示的应用程序用例与 UET 配置文件的映射。

2.2.2.1 配置文件协商和配置文件间互操作性

表 2-6 所示的逻辑优先级与每个配置文件相关联,用于在源 FEP 和目标 FEP 支持重叠的配置文件时解决冲突。

UET libfabric 端点地址(在 2.2.5.1 节中指定)包含一个 Fabric Endpoint Capabilities 字段,该字段指示 Fabric 端点支持的配置文件。如果源 FEP 和目标 FEP 支持的配置文件存在重叠,则必须使用逻辑优先级最高的通用配置文件进行 FEP 之间的通信。AI Base 配置文件是 AI Full 和 HPC 配置文件的子集。因此,始终可以使用 AI Base 配置文件。HPC 配置文件不是 AI Full 配置文件的超集。但是,2.2.5.4.1.2 节中讨论的可延迟发送是唯一一项不受 HPC 配置文件支持的 AI Full 功能。因此,AI Full 配置文件和 HPC 配置文件可以互操作,但须遵守以下限制:

• 操作必须仅限于 AI Full 配置文件支持的操作;

• HPC 配置文件必须将可延迟发送操作视为与发送操作相同;

• HPC 配置文件必须将可延迟标记发送操作视为与标记发送操作相同。

2.2.3 配置信息

libfabric UET 提供程序配置参数如表 2-7 所示。

字数:
  • UET_PROVIDER_SERVICE_PATH: 环境变量,用于指定可选服务配置文件的路径名,该文件包含用户定义的服务名称字符串和相关索引。服务名称字符串可用作 fi_getinfo() API 的参数,用于为服务分配索引或索引范围。文件格式为每行一个服务条目,格式如下:service_name start_index num_indices 其中 service_name 是一个字符串,最大长度为 64 个字符。start_index 和 num_indices 为整数,其中 (start_index + num_indices] <= 4096
  • UET_PROVIDER_MAX_EAGER_SIZE: 会合协议的最大急切(eager)数据量(以字节为单位)。SES 规范对急切数据的定义如下:初始会合请求可以包含与其一起传输的“急切”数据部分。急切传输是指在目标端确定传输缓冲区之前进行的负载传输。

2.2.4 JobID

JobID 是 UET 寻址的一部分,在 SES 头中作为 ses.JobID 字段携带,用于授权。JobID 必须由特权实体分配。特权实体必须按照 2.2.4.1 节或 2.2.5.3.5.1 节中的说明,将分配的 JobID 提供给提供程序内核驱动程序。分配后,JobID 可以传递给 libfabric 用户空间软件,但 libfabric 用户空间软件提供给 UET 提供程序的 JobID 必须在硬件环境中进行验证。指定了多种分配 JobID 的方法:1. 在作业初始化时分配 JobID 2. 在 libfabric 端点创建时分配 JobID 3. 备用 JobID 分配

2.2.4.1 在作业初始化时分配 JobID

特权实体(例如作业启动器)可以在作业初始化时分配 JobID。在作业初始化时执行 JobID 分配时,特权实体必须通过 UET 控制 API 与提供程序内核驱动程序配置 {OS 进程 ID,服务名称} => {JobID} 映射,如图 2-4 所示。特权实体还可以配置本地 UET 地址和安全绑定的组件作为映射的一部分。

UET控制API JobID映射参数如表2-8所示。

UET 控制 API JobID 映射请求的“C”结构表示如图 2-5 所示。

可以使用 uet_ctrl_job_id_map_req 结构体的 sec_bindings 字段为整个 JobID 映射分配安全绑定。或者,在 UET Control API 的 Linux 实现中(参见 2.2.11 节),可以使用一系列 UET_NL_ATTR_SEC_BINDINGS Netlink 属性为每个已分配的资源索引分配安全绑定。可以使用 UET Control API 的 JobID 取消映射请求来移除 JobID 映射。UET Control API JobID 取消映射请求的“C”结构体表示如图 2-6 所示。

可以将多个 JobID 分配给同一个 {OS PID,服务名称}。当多个 JobID 分配给同一个 {OS PID,服务名称} 时,必须使用 libfabric FI_AV_AUTH_KEY 功能来选择与数据传输操作关联的 JobID。例如,多个 JobID 允许服务器的单个 libfabric 端点与多个客户端作业进行通信。另一个用例是多个作业需要相互通信。当特权实体在作业初始化时配置 JobID 时,提供程序内核驱动程序必须维护已配置的 JobID 映射以供后续使用。特权实体还可以将 JobID 传递给用户空间应用程序,用作后续 libfabric API 调用的参数。UET 提供程序必须为每个 libfabric 端点支持至少一个 JobID,并且可以支持多个。如果每个 libfabric 端点都提供单个 JobID,则该 JobID 可以包含在 libfabric auth_key 属性中(FI_AV_AUTH_KEY 功能也可用于支持每个端点使用单个 JobID)。如果每个 libfabric 端点支持多个 JobID,则必须使用 fi_av_insert_auth_key() API 将 JobID 插入到绑定到端点的地址向量中(即,将 JobID 作为授权密钥插入)。插入的 JobID 可以用于:

• 已发布的接收缓冲区的授权;

• 注册内存区域的授权;以及

• 选择用于消息传输操作的 JobID。

当 auth_key_size 属性设置为 FI_AV_AUTH_KEY 时,所有授权密钥都与地址向量关联。当支持多个 JobID 时,auth_key_size 必须设置为 FI_AV_AUTH_KEY。否则,auth_key_size 必须设置为 0 或 3。当 auth_key_size 设置为 0 时,UET 提供程序将代表用户提供分配的 JobID。当 auth_key_size 设置为 3 时,JobID 必须包含在 auth_key 属性中。max_ep_auth_key 域属性指示每个 libfabric 端点支持的最大授权密钥数量。为方便起见,定义以下术语:

• 间接 JobID 方法 (auth_key_size = 0) – 这是默认行为

• 直接 JobID 方法 (auth_key_size = 3)

• AV JobID 方法 (auth_key_size = FI_AV_AUTH_KEY)

HPC 配置文件必须支持 AV JobID 方法。AV JobID 方法必须支持 fi_av_insert_auth_key 和 fi_av_lookup_auth_key libfabric API。在创建 libfabric 端点时,也可能进行 JobID 分配,具体操作请参见第 2.2.5.3.5.1 节,如图 2-9 所示。

2.2.4.2 备用 JobID 分配

提供程序配置可以启用备用 JobID 分配。在此模式下,如果无法通过先前的方法确定端点的 JobID,则会为其分配一个备用 JobID。备用 JobID 的值为 16777215。启用备用 JobID 支持后,端点的启动器 ID 来源于 UET_PROVIDER_INITIATOR_ID 环境变量。如果未设置该环境变量,端点创建必须失败。

2.2.4.3 授权

本节描述的授权流程必须在绝对寻址模式下实现。相对寻址模式下无需实现这些流程,因为 JobID 是用于定位缓冲区和内存区域的寻址信息的组成部分。有关绝对寻址和相对寻址模式的描述,请参阅 SES 规范。授权允许控制对接收缓冲区和已注册内存区域的访问。JobID 用于授权访问接收缓冲区和已注册内存区域。SES 规范中定义的具体要求如下:

• 实现必须允许为一个 JobID 公开缓冲区和内存区域。

• 实现必须允许为“任意”JobID 公开缓冲区和内存区域。

使用 fi_msg() API 之一发布缓冲区时,将确定与接收缓冲区关联的 JobID。使用 fi_mr API 注册内存区域时,将确定与内存区域关联的 JobID。以下小节详细说明了确定与已发布的接收缓冲区或已注册内存区域关联的 JobID 的流程。授权是通过检查 SES 标头中的 ses.JobID 字段是否允许访问目标接收缓冲区或已注册内存区域来执行的。

2.2.4.3.1 无标签消息缓冲区授权

本节介绍如何管理无标签消息缓冲区的授权要求。根据所使用的 JobID 方法是间接、直接还是 AV JobID 方法,缓冲区授权的 JobID 获取方式有所不同。使用间接 JobID 方法时,UET 提供程序会提供分配的 JobID,并且只有 SES 标头中带有该 ses.JobID 字段的操作才能获得无标签消息缓冲区访问权限。使用直接 JobID 方法时,无标签消息缓冲区授权的 JobID 直接从 libfabric 端点的 auth_key 属性中获取,并且只有 SES 标头中带有该 ses.JobID 字段的操作才能获得缓冲区访问权限。使用 AV JobID 方法时,当设置了 FI_AV_AUTH_KEY 标志时,使用 fi_recvmsg() API 的 src_addr 参数确定用于无标记消息缓冲区授权的 JobID。在这种情况下,当 JobID 插入到绑定到 libfabric 端点的地址向量时,src_addr 将被视为 fi_av_insert_auth_key() API 返回的源授权密钥。只有当 SES 标头中带有此 ses.JobID 字段时,才能授权缓冲区访问。在所有其他情况下(例如,使用 fi_recv() API、使用 fi_recvv() API 且未设置 FI_AV_AUTH_KEY):

- 已发布的缓冲区必须适用于任何 JobID,并且

- src_addr 参数引用的 UET 地址的组成部分可用于根据 FI_DIRECTED_RECV 语义将接收到的消息定向到特定缓冲区。

2.2.4.3.2 标记消息缓冲区授权

标记消息缓冲区的授权要求与 2.2.4.3.1 节中未标记消息缓冲区的授权要求相同。

2.2.4.3.3 内存区域授权

本节介绍如何管理已注册内存区域的授权要求。要将已注册内存区域与 JobID 关联,必须使用 fi_mr_regattr() API。当 fi_mr_regattr() 的 attr 参数的 auth_key_size 字段为 0 时,该内存区域必须适用于任何 JobID。当 fi_mr_regattr() 的 attr 参数的 auth_key_size 字段为 3 时,该内存区域必须与 libfabric 端点的 auth_key 属性中携带的 JobID 关联。当 fi_mr_regattr() 的 attr 参数的 auth_key_size 字段设置为 FI_AV_AUTH_KEY 时:

• fi_mr_regattr() 的 attr 参数的 auth_key 字段必须指向一个用户定义的 fi_mr_auth_key 结构体,该结构体指定:

一个地址向量,以及

一个已插入该地址向量的地址。

• 该内存区域必须与 fi_mr_auth_key 结构体中指定地址的授权密钥所表示的 JobID 相关联。 在所有其他情况下(例如,使用 fi_mr_regattr( 以外的 fi_mr() 注册 API),)),该内存区域必须适用于任何 JobID。当已注册的内存区域与某个 JobID 关联时,必须仅对 SES 标头中携带该 ses.JobID 字段的操作授权访问。

2.2.4.4 数据传输操作的 JobID 选择

使用间接 JobID 方法,提供程序引用 SES 标头中已分配的 ses.JobID 字段以方便数据传输操作。在直接 JobID 方法中,数据传输操作的 SES 标头中的 ses.JobID 字段必须直接从 libfabric 端点的 auth_key 属性中获取。使用 AV JobID 方法,数据传输操作的 SES 标头中的 ses.JobID 字段必须根据 libfabric API 的 fi_addr_t dest_addr 参数(即,将目标地址插入地址向量时与其关联的授权密钥)确定。

2.2.5 Libfabric API

本规范针对 libfabric v2.0 版本。Libfabric 提供了许多 API,目前已记录在表 2-9 中总结的几组中。

本规范并未明确涵盖每个单独的 API。相反,本规范将:

• 详细介绍的 API 仅限于第 2.2 节中确定的四个主要 API 类别(即控制、通信、完成和数据传输)中的关键 API。

• 其他 libfabric API 的要求在第 2.2.5.5 节中指定。

• 除非另有明确说明,否则所有 libfabric API 都应受支持。

一些 libfabric API 还包含一些未包含在 2.2.2 节中规定的 UET 配置文件参数要求中的参数,并且这些参数的子集需要 UET 提供商进行特殊处理。我们已尽力识别此类参数并指定所需的处理。图 2-7 提供了关键 libfabric 对象与相关 API 之间关系的顶层描述。该图旨在提供上下文,以便于理解本规范的后续文本。创建对象的典型 API 流程总结如下:

• fi_getinfo() API 用于识别本地可用的提供程序及其功能。 fi_getinfo() 返回 fi_info 结构列表。

• 应用程序选择与所需提供程序关联的 fi_info 结构,并将 fi_info 结构用作 fi_fabric() API 的参数,该 API 创建一个 fabric 对象。 在 libfabric 中,fabric 代表一个网络。

• fi_eq_open() API 用于创建绑定到 fabric 的事件队列。 事件队列用于报告异步控制操作和事件的完成情况。

• fi_domain() API 用于创建绑定到 fabric 的域对象。 在 libfabric 中,域代表一个 NIC。

• fi_endpoint() API 用于创建绑定到域的端点对象。 在 libfabric 中,端点代表一个传输级通信门户。

• fi_cq_open() API 用于创建一个或多个完成队列。 完成资源(即完成队列或完成计数器)用于报告已提交数据传输操作的结果。

• fi_cntr_open() API 可用于创建一个或多个完成计数器。

• fi_ep_bind() API 用于将资源绑定到端点,例如事件队列、完成队列、完成计数器、地址向量或共享的发送/接收上下文。

• fi_mr_reg() API 用于创建绑定到域的内存区域。

• fi_mr_bind() API 用于将内存区域绑定到端点(而不是域)。 UET 要求内存区域绑定到端点,如表 2-4 所示。

• fi_av_open() API 用于在域下创建地址向量,并将其绑定到端点。 地址向量用于有效地表示目标端点。

• fi_av_insert() API 用于在地址向量中插入一个或多个条目。

• 数据传输 API 用于端点通信

2.2.5.1 Libfabric 寻址

Libfabric 提供灵活的端点寻址,可用的地址格式由枚举定义。枚举中添加了一个新值 FI_ADDR_UET,用于标识 UET 地址格式。无需支持以 FI_ADDR_STR 格式表示 UET libfabric 端点地址。UET libfabric 端点地址的组成部分如表 2-10 所示。

注意:

  1. 有效标志允许在 fi_getinfo() API(参见 2.2.5.2.2 节)和 fi_endpoint() API(参见 2.2.5.3.5 节)上请求 UET 地址的特定组件。

UET 地址的资源索引字段使支持多服务的多线程应用程序能够为每个服务打开一个 libfabric 端点。每个服务都会获得一个唯一的索引,用于区分端点。

Libfabric 端点地址在打开 libfabric 端点时分配,如第 2.2.5.3 节所述。 UET Libfabric 端点地址的“C”结构表示如图 2-8 所示。

2.2.5.2 发现 API

发现 API 用于发现可用的 libfabric 通信服务。 本节讨论以下两个发现 API:

2.2.5.2.1 fi_version() API

fi_version() API 用于获取 libfabric 版本。该 API 返回一个编码版本,可以使用 FI_MAJOR () 和 FI_MINOR () 宏进行解码。该信息可用于确保 libfabric 版本满足应用程序所需的最低版本要求。对于 UET,此最低版本应为主版本 2 和次版本 0。

2.2.5.2.2 fi_getinfo() API

fi_getinfo() API 用于识别本地可用的提供程序及其功能。表 2-11 中 fi_getinfo() 的参数需要进一步说明:

  • 节点参数通常设置为 NULL,并被提供商忽略,但可以用作过滤器来限制返回的提供商。对于 UET,如果节点参数非空,则必须指向 UET 地址。如果节点参数非空且设置了 FI_SOURCE 标志,则 UET 提供商应该根据 UET 地址的有效字段过滤返回的信息(参见表 2-10)。如果节点参数非空且未设置 FI_SOURCE 标志,则 UET 提供商不应该返回信息
  • 以前,服务参数通常被设置为 NULL,并被提供商忽略。对于 UET,服务参数可以包含服务名称字符串。该字符串可以是与 UET 支持的特定服务关联的预定义值,也可以是提供商从可选服务配置文件中读取的用户定义值,如第 2.2.3 节所述。预定义服务字符串集如下表 1-10 所示。如果服务配置文件中出现预定义服务字符串值,则服务配置中定义的映射必须优先。

预定义的 UET 服务名称:

可以为一个服务分配多个资源索引。可扩展端点(使用 fi_scalable_ep() API 创建)必须为每个接收上下文分配一个唯一的资源索引(参见 fi_rx_context() API)。使用 fi_endpoint() API 创建的端点的 UET 地址必须分配一个应用程序可见的资源索引(该端点还可以关联一个额外的资源索引,该资源索引不为应用程序可见,但用作提供者之间的控制通道)。

2.2.5.3 通信和完成 API

通信和完成 API 用于执行数据传输所需的设置并报告数据传输操作结果。本节将讨论以下通信和完成 API:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int fi_fabric(struct fi_fabric_attr *attr, struct fid_fabric **fabric,
 void *context);
<https://ofiwg.github.io/libfabric/main/man/fi_fabric.3.html>
​
int fi_eq_open(struct fid_fabric *fabric, struct fi_eq_attr *attr,
 struct fid_eq **eq, void *context);
<https://ofiwg.github.io/libfabric/main/man/fi_eq.3.html>
​
int fi_domain(struct fid_fabric *fabric, struct fi_info *info,
 struct fid_domain **domain, void *context);
<https://ofiwg.github.io/libfabric/main/man/fi_domain.3.html>
​
int fi_mr_reg(struct fid_domain *domain, const void *buf, size_t len,
 uint64_t access, uint64_t offset, uint64_t requested_key,
 uint64_t flags, struct fid_mr **mr, void *context);
uint64_t fi_mr_key(struct fid_mr *mr);
<https://ofiwg.github.io/libfabric/main/man/fi_mr.3.html>
​
int fi_endpoint(struct fid_domain *domain, struct fi_info *info,
 struct fid_ep **ep, void *context);
int fi_ep_bind(struct fid_ep *ep, struct fid *fid, uint64_t flags);
<https://ofiwg.github.io/libfabric/main/man/fi_endpoint.3.html>
int fi_getname(fid_t fid, void *addr, size_t *addrlen);
<https://ofiwg.github.io/libfabric/main/man/fi_cm.3.html>
​
int fi_cq_open(struct fid_domain *domain, struct fi_cq_attr *attr,
 struct fid_cq **cq, void *context);
<https://ofiwg.github.io/libfabric/main/man/fi_cq.3.html>
​
int fi_cntr_open(struct fid_domain *domain, struct fi_cntr_attr *attr,
 struct fid_cntr **cntr, void *context);
<https://ofiwg.github.io/libfabric/main/man/fi_cntr.3.html>
​
int fi_av_open(struct fid_domain *domain, struct fi_av_attr *attr,
 struct fid_av **av, void *context);
int fi_av_insert(struct fid_av *av, void *addr, size_t count,
 fi_addr_t *fi_addr, uint64_t flags, void *context);
<https://ofiwg.github.io/libfabric/main/man/fi_av.3.html>
2.2.5.3.1 fi_fabric() API

调用 fi_fabric() API 来打开 Fabric 网络提供程序对象。Fabric 表示访问单个物理或虚拟网络的硬件和软件资源的集合。指向 Fabric 属性结构体的指针是 fi_fabric() 的参数。fi_getinfo() API 返回的 fi_info 结构体包含指向 Fabric 属性结构体的指针。

2.2.5.3.2 fi_eq_open() API

调用 fi_eq_open() API 来为 Fabric 创建新的事件队列。事件队列用于控制操作,不用于完成数据传输操作(例如发送和接收)。事件队列用于收集和报告异步控制操作和事件的完成情况。 EQ 用于控制与数据传输操作无直接关联的事件,例如:

• 异步完成 libfabric 控制 API 调用

某些 libfabric 控制 API 支持同步或异步操作

• 针对结构资源(例如完成队列或端点)问题的异步错误通知。EQ 通常完全以软件实现。

EQ 也可以使用 fi_domain_bind API 绑定到域。UET 提供程序必须支持事件队列。每个 libfabric 端点必须至少支持一个事件队列。

2.2.5.3.3 fi_domain() API

调用 fi_domain() API 来在结构上打开访问域。域是与结构之间的逻辑连接,通常对应于物理或虚拟网卡。fi_domain() API 将指向 fi_info 结构的指针作为参数。fi_getinfo() API 返回的 fi_info 结构包含指向域属性结构的指针。

2.2.5.3.4 fi_mr_reg() 和 fi_mr_key() API

内存缓冲区必须先在资源域中注册,然后才能用作远程 RMA 或原子数据传输的目标。此外,Fabric 提供程序可以要求数据缓冲区在用于本地传输之前进行注册(例如,缓冲区是写入操作的源或读取操作的目标)。fi_mr_reg() API 用于在域中注册内存区域。使用 fi_mr_bind() API 将内存区域绑定到端点。fi_mr_key() API 用于获取远程端点访问已注册内存区域所需的密钥。Libfabric 提供了一些选项,允许应用程序或提供程序为内存区域分配密钥。UET 提供程序应该支持用户分配密钥,因此不应要求使用 FI_MR_PROV_KEY 模式标志。

如果应用程序使用约定,且约定中相应的键值众所周知,则支持用户分配的键可以使应用程序避免交换内存键。

2.2.5.3.4.1 内存密钥格式

为了实现互操作性,内存区域密钥的格式已标准化,如表 2-13 所示。

  • 0 => 内存区域不得用作幂等传输操作的目标。 1 => 内存区域可以用作幂等传输操作的目标(即,没有绑定到该内存区域的完成计数器)。幂等操作可以提高传输协议的效率。
  • 0 => 内存区域不支持优化的非匹配标头(优化的非匹配标头格式定义在 UET SES 规范中;优化是指比标准 SES 请求标头更小的标头)。 1 => 内存区域支持优化的非匹配标头

表 2-13 所示的内存区域密钥格式必须用于用户提供的密钥和提供方提供的密钥。完整的 64 位密钥格式必须通过 fi_mr() API 传递。将提供位掩码定义,以协助生成所需格式的密钥。RKEY 字段的大小固定为 48 位,但支持的 RKEY 值范围必须基于 fi_domain_attr 结构中 mr_key_size 属性的值。如果 mr_key_size 小于 6,则未使用的最高有效位必须为 0。提供方提供的 RKEY 的格式因提供方而异(因为该格式仅在分配提供方本地有效)。提供方实现必须选择如何使用 RKEY 来标识已注册的内存区域(例如,密钥可以用作表索引、哈希查找元组的一部分等)。 UET 提供商可以选择将 RKEY 划分为两个部分,一部分用于承载内存密钥,另一部分用于承载额外的身份验证信息。[0..4095] 范围内的 RKEY 值值得进一步讨论,因为在某些情况下,这些值可以与优化的不匹配 SES 标头结合使用。当满足表 2-14 中指定的标准时,应使用优化的不匹配 SES 标头。本节中指定的标准适用的 RMA 操作与 fi_rma() API 组 https://ofiwg.github.io/libfabric/v1.20.1/man/fi_rma.3.html 中定义的 libfabric API 相关联。

当使用优化的不匹配 SES 标头进行 RMA 操作时,RKEY/INDEX 值必须包含在 SES 标头的 ses.resource_index 字段中。使用小型 RMA SES 标头进行 RMA 操作必须满足的条件如表 2-15 所示。当满足表 2-15 中指定的条件时,应使用小型 RMA SES 标头进行 RMA 操作。

如果优化的非匹配 SES 报头的使用标准不满足,并且小型 RMA SES 报头的使用标准也不满足,则必须使用标准 SES 报头进行 RMA 操作。使用 RUDI 数据包传送模式进行 RMA 操作必须满足的标准如表 2-16 所示。RUDI 数据包传送模式针对幂等操作进行了优化,并在 PDS 可靠性规范中进行了描述。如果支持,则在满足表 2-16 中指定的标准时,应该使用 RUDI 数据包传送模式。

用户提供的和提供程序提供的内存密钥都可以标记为 IDEMPOTENT_SAFE 和/或 OPTIMIZED。即使配置了 FI_MR_PROV_KEY,UET 提供程序也应该遵守 fi_mr() API 的 requested_key 参数中的 IDEMPOTENT_SAFE 和 OPTIMIZED 位。如果用户尝试将完成计数器绑定到标记为 IDEMPOTENT_SAFE 的内存区域,UET 提供程序必须使绑定操作失败。如果请求了提供程序提供的 OPTIMIZED 密钥但无法分配,则提供程序应该回退到非优化操作。RKEY 的范围要求在表 2-17 中指定。

2.2.5.3.5 fi_endpoint() 和 fi_ep_bind() API

fi_endpoint() API 用于在域中打开活动端点。端点是传输层通信门户。数据传输接口与活动端点相关联,这些端点通常具有发送和接收队列。fi_endpoint() API 以 fi_info 结构作为参数。fi_info 参数通常是 fi_getinfo() API 返回的 fi_info 结构。fi_info 结构包含一个源地址字段,该字段用于打开活动端点。源地址字段可用于请求分配特定的 UET 地址。可以使用 UET 地址标志字段中的有效位来请求 UET 地址的选定组成部分。Libfabric 端点地址分配可能是一个多阶段过程,其中端点地址的一部分可以在作业初始化时分配,或者通过 fi_getinfo() API 分配;其余部分在端点打开时分配。应用程序只能通过调用 fi_getname() API(详见第 2.2.5.3.6 节)来获取其完整的 UET 地址。JobID 可以在作业初始化时或端点打开时分配。JobID 必须由特权实体写入硬件。

UET 提供程序必须支持以下 libfabric 端点类型:

• FI_EP_DGRAM

• FI_EP_RDM

每个 libfabric 端点都属于单一类型,要么是 FI_EP_DGRAM,要么是 FI_EP_RDM。fi_ep_bind() API 用于将资源与端点关联,例如事件队列、完成队列、完成计数器、地址向量或共享的发送/接收上下文。

2.2.5.3.5.1 UET 地址分配架构

以下项目总结了分配 UET 地址字段的流程:

• UET 提供程序向内核模式驱动程序发出请求,该请求被中继到特权用户模式进程,该进程是负责 UET 地址分配的配置系统的一部分。

• 该请求包含有关正在打开的端点的信息。

• 特权实体返回所需的地址信息。

• 还可以返回其他信息,例如 JobID 和安全域绑定。图2-9给出了UET地址分配流程的架构图

图 2-9 所示的步骤如下:

  1. UET 提供程序向内核驱动程序发出地址分配请求。
  2. 内核驱动程序通过 UET 控制 API 将请求转发给特权用户进程。
  3. 特权用户进程与配置系统通信并返回请求的地址信息。
  4. 内核驱动程序将 JobID 验证信息和安全绑定编程到 NIC 硬件中。
  5. 内核驱动程序将不包含安全绑定的响应转发给 UET 提供程序。 与此架构相关的要求如下:

• UET 提供程序必须向内核驱动程序发送地址分配请求。

• 地址分配请求必须包含以下信息:

o FEP IP 地址

▪ FEP IP 地址是 UET 提供程序地址分配请求的一个参数。

▪ FEP IP 地址参数用作 UET 地址的一部分。

▪ UET 地址分配请求不配置 NIC 接口的 IP 地址。

o 操作系统进程 ID

o 服务名称

• 在 Linux 实现中,UET 提供程序应使用 Netlink 接口与内核驱动程序进行地址分配通信。

• 内核驱动程序必须使用 UET 控制 API 将地址分配请求中继到特权用户进程。

• 特权用户进程必须使用 UET 控制 API 将地址分配响应返回给内核驱动程序。

• 在 Linux 实现中,内核驱动程序必须仅接受以 root 身份运行的特权进程的响应。

• 如果在作业初始化时未提供(参见 2.2.4 节),地址分配响应必须包含以下信息:

o 作业 ID

▪ 如果请求进程在作业初始化时配置了一个作业 ID,则响应中提供的作业 ID 应优先。

▪ 如果请求进程在作业初始化时配置了多个作业 ID,并且启用了 FI_AV_AUTH_KEY 功能,则响应中提供的作业 ID 应被忽略。

o 地址模式

o PIDonFEP

o 发起方 ID

• 地址分配响应可以选择性地包含以下信息:

o 加密操作的安全绑定(参见 2.2.9 节)

▪ 安全绑定按照 2.2.4.1 节中的规定分配

o 起始资源索引

o 资源索引数量

▪ 响应中提供的资源索引绑定应优先于其他索引配置方法。

• 内核驱动程序必须将 JobID 验证信息和安全绑定编程到 NIC 硬件中。

• 内核驱动程序必须将不包含安全绑定的地址分配响应转发给 UET 提供程序,并且在 Linux 实现中转发响应时应使用 Netlink 接口。 表 2-18 列出了 UET 控制 API 地址分配请求的参数。

UET控制API地址分配响应的组成参数如表2-19所示。

UET控制API地址分配请求和响应的C结构表示如图2-10所示。

2.2.5.3.6 fi_getname() API

调用 fi_getname() API 来检索 libfabric 端点的本地 UET 地址。该调用返回一个地址对象,该对象通常与作业的其他端点共享。

2.2.5.3.7 fi_cq_open() 和 fi_cntr_open() API

完成资源用于报告已提交数据传输操作的结果。完成资源可以是完成队列(通常由硬件实现)或完成计数器(可以由硬件或软件实现)。调用 fi_ep_bind() API 将完成资源绑定到端点。完成计数器仅返回已完成操作的数量。计数器旨在用作轻量级完成对象,每当发生已识别类型的数据传输时,计数器的值就会递增,从而避免了将完成队列条目传送给应用程序的开销。完成计数器可供 MPI 等应用程序使用。调用 fi_cntr_open() API 来打开完成计数器。调用 fi_cq_open() API 来打开 CQ。支持多种预定义的 CQ 条目格式。此外,还支持特定于提供程序的 CQ 条目格式。UET 提供程序必须支持完成队列。每个配置文件对完成计数器的要求在表 2-20 中指定。

支持完成计数器所需的配置文件必须同时支持 FI_CNTR_EVENTS_COMP 和 FI_CNTR_EVENT_BYTES 事件类型。

2.2.5.3.8 fi_av_open() 和 fi_av_insert() API

地址向量用于将更高级别的地址映射到特定于架构的地址。AV 的目的是将更高级别的地址与更简单、更高效的值关联起来,以便 libfabric API 以与架构无关的方式使用该值。

调用 fi_av_open() API 创建地址向量,调用 fi_ep_bind() API 将地址向量绑定到端点,并调用 fi_av_insert() API 将目标端点的地址插入地址向量。fi_av_insert() API 返回 fi_addr_t 类型的映射地址,该地址将传递给数据传输 API 以识别目标端点,从而无需在每次数据传输时都传递目标端点的完整地址。地址向量有两种类型:

• FI_AV_MAP 插入到 AV 中的地址会映射到原生 Fabric 地址,以供应用程序使用。使用 FI_AV_MAP 需要应用程序存储与每个插入地址关联的返回 fi_addr_t 值。FI_AV_MAP 在 libfabric v2.0 中已弃用。枚举类型将保留,但行为将类似于 FI_AV_TABLE。

• FI_AV_TABLE 插入到 FI_AV_TABLE 类型的 AV 中的地址可以通过简单索引访问。使用 FI_AV_TABLE 时,返回的 fi_addr_t 是一个索引,插入地址的索引与其在表中的插入顺序相同。第一个插入到 FI_AV_TABLE 中的地址的索引为 0,后续插入的地址将使用连续的索引。在同一 AV 上的插入调用之间将分配连续的索引。

AV 属性结构体 fi_av_attr 包含一个 name 字段和一个 map_addr 字段,用于在进程之间共享 AV。UET 提供程序必须支持 FI_AV_TABLE 类型。未指定的类型 FI_AV_UNSPEC 必须被视为 FI_AV_TABLE 类型。

使用 FI_AV_TABLE 的一种方法是按顺序插入每个等级的地址,使 AV 表索引与等级编号相同。

2.2.5.4 OFI 数据传输 API

本节介绍以下几组数据传输 API:

• fi_msg() https://ofiwg.github.io/libfabric/v1.20.1/man/fi_msg.3.html

• fi_tagged() https://ofiwg.github.io/libfabric/v1.20.1/man/fi_tagged.3.html

• fi_rma() https://ofiwg.github.io/libfabric/v1.20.1/man/fi_rma.3.html

• fi_atomic() https://ofiwg.github.io/libfabric/v1.20.1/man/fi_atomic.3.html

• fi_collective() https://ofiwg.github.io/libfabric/v1.20.1/man/fi_collective.3.html

2.2.5.4.1 fi_msg() API

fi_msg() API 用于执行消息数据传输操作。其中包括用于发布接收缓冲区以接收传入消息的 API,以及用于启动传出消息传输的 API。FI_EP_DGRAM 和 FI_EP_RDM 端点必须支持 fi_msg() API。fi_msg() 接收 API 的要求总结在表 2-21 中。

fi_recv: 将数据缓冲区发布到相应端点的接收队列。已发布的接收缓冲区将按照其发布顺序进行搜索,以匹配发送。消息边界保持不变。src_addr 参数可用于指示应发布缓冲区以接收来自特定远程端点的传入数据

fi_recvmsg() API 支持使用标志参数对每次调用的接收操作进行更精细的控制

UET 提供商应该为消息和标记消息分配独立的接收队列(即已发布的接收缓冲区列表)。表 2-22 总结了 fi_msg() 发送 API 的要求,并展示了 API 与 UET SES 操作码的映射。

fi_inject() API 是 fi_send() 的优化版本,具有以下特点:

• 调用返回后,数据缓冲区可立即重用

• 如果传输成功完成,则不会写入任何 CQ 条目

• 当与 FI_EP_RDM 类型的 libfabric 端点一起使用时,并且无法传递消息时,必须写入错误 CQ 条目(此要求适用于所有注入操作)

2.2.5.4.1.1 意外消息

必须使用 SES 规范中定义的方法来支持意外消息,其中在目标上使用哪种方法取决于供应商。发起方必须对所有目标行为做出适当的响应。

2.2.5.4.1.2 消息汇合 (Rendezvous)

SES 规范目前定义了两种类型的汇合协议,分别称为:

• 汇合和

• 可延迟发送。

AI Full 配置文件必须支持可延迟发送选项,而 HPC 配置文件必须支持汇合选项。此外,SES 规范描述了两种汇合方法,用于将 *CCL 发送和接收 API 映射到 libfabric 和 UET 语义 API。这两种方法都利用了 *CCL 插件实现的协议,这些插件位于 libfabric API 之上。一种方法利用 fi_tagged() API,另一种方法基于 fi_rma() API。对于 AI Full 配置文件,大小 >= UET_PROVIDER_MSG_RENDEZVOUS_SIZE 字节的消息应使用 UET_DEFERRABLE_SEND 语义操作码发送。对于 HPC 配置文件,当满足以下条件时,应使用 UET_RENDEZVOUS_SEND 语义操作码发送消息:

• 消息大小 >= UET_PROVIDER_MSG_RENDEZVOUS_SIZE 字节,并且

• 源缓冲区与已注册为远程读取访问的本地内存区域相关联作为 UET_RENDEZVOUS_SEND 操作的一部分发送的急切数据量必须 <= UET_PROVIDER_MAX_EAGER_SIZE 字节。

2.2.5.4.2 fi_tagged() API

fi_tagged() API 用于执行标记数据传输操作。其中包括用于发布传入消息的接收缓冲区的 API 和用于启动传出消息传输的 API。 FI_EP_DGRAM 端点不支持 fi_tagged() API。AI Full 和 HPC 配置文件必须支持 fi_tagged() API。fi_tagged() 接收 API 要求总结在表 2-23 中。

fi_trecv: 与 fi_recv() 类似,但带有标签。已发布的接收缓冲区将按其发布顺序进行搜索,以匹配发送。ignore 参数包含一个应用于标签的位掩码,以支持通配符标签匹配。AI Full 和 HPC 配置文件必须支持 API。AI Full 配置文件仅支持精确匹配标签。如果不支持通配符标签,则当设置了任何忽略位时,UET 提供商必须拒绝 API 请求。HPC 配置文件必须支持通配符标签匹配。

表 2-24 总结了 fi_tagged() 发送 API 的要求,并展示了 API 到 UET SES 操作码的映射。

2.2.5.4.2.1 标记消息发起方 ID 匹配

接收到的标记消息的 SES 报头包含一个 ses.initiator 字段,该字段用作匹配条件的一部分。已发布的标记缓冲区关联的发起方 ID 取决于 fi_tagged() API 的 src_addr 参数。如果 src_addr 参数未设置为 FI_ADDR_UNSPEC,则仅当标记与 SES 报头中的 ses.match_bits 字段匹配,并且 SES 报头中的 ses.initiator 字段与 src_addr 参数所引用的 UET 地址的发起方 ID 部分匹配时,才必须匹配已发布的标记缓冲区。src_addr 参数所引用的 UET 地址的其他部分可用于根据 FI_TAGGED_DIRECTED_RECV 语义将接收到的消息定向到特定缓冲区。如果 src_addr 参数设置为 FI_ADDR_UNSPEC,则 ses.initiator 字段不得用作匹配条件的一部分。AI Full 和 HPC 配置文件的实现必须支持将 FI_ADDR_UNSPEC 与 fi_tagged() API 结合使用。AI Full 配置文件的实现应支持将 fi_tagged() API 的 src_addr 参数设置为引用特定的源 UET 地址。提供商可以指示不支持 FI_ADDR_UNSPEC,并且支持通过 FI_EXACT_DIRECTED_RECV 功能将 src_addr 参数设置为引用特定的源 UET 地址。HPC 配置文件的实现必须支持将 fi_tagged() API 的 src_addr 参数设置为引用特定的源 UET 地址。与 FI_AV_TABLE 一起使用时,线路上 ses.initiator 的值应为该表的索引。 src_addr 的发起方 ID 部分在此处应该就是 CCL/MPI 等级,并且两者应该匹配。

2.2.5.4.2.2 标记消息汇合

标记消息汇合要求与 2.2.5.4.1.2 节中规定的消息汇合要求类似。对于 AI Full 配置文件,大小 >= UET_PROVIDER_TAG_RENDEZVOUS_SIZE 字节的标记消息应使用 UET_DEFERRABLE_TSEND 语义操作码发送。对于 HPC 配置文件,大小 >= UET_PROVIDER_TAG_RENDEZVOUS_SIZE 字节的标记消息应使用 UET_RENDEZVOUS_TSEND 语义操作码发送。作为 UET_RENDEZVOUS_TSEND 操作的一部分,发送的 Eager 数据量必须小于等于 UET_PROVIDER_MAX_EAGER_SIZE 字节。

2.2.5.4.3 fi_rma() API

fi_rma() API 用于执行远程内存访问操作。它包含用于读取和写入操作的 API。fi_rma() API 不支持 FI_EP_DGRAM 端点。表 2-25 总结了 fi_rma() API 的要求,并展示了这些 API 与 UET SES 操作码的映射。

表 2-25 总结了 fi_rma() API 要求,并展示了 API 到 UET SES 操作码的映射。

2.2.5.4.4 fi_atomic() API

fi_atomic() API 支持远程原子操作。其 API 可用于:

• 向远程内存发起原子操作(有时称为非获取原子操作)。

• 向远程内存发起原子操作并获取初始值(称为获取原子操作)。

• 向远程内存发起原子比较操作并获取初始值(这是一种获取原子操作)。

• 查询提供程序是否支持特定的原子操作。

fi_atomic() API 不支持 FI_EP_DGRAM 端点。UET 提供程序必须支持批量非获取原子操作;但是,获取原子操作必须仅限于指定数据类型的单个单元。表 2-26 总结了 fi_atomic() API 的要求,并展示了 API 与 UET SES 操作码的映射。

2.2.5.4.5 集合 API

集合操作是一种群组通信交换,涉及多个对等体与参与集合调用的其他对等体交换数据。集合操作可以被认为是一组对等端点之间协调的原子操作。

2.2.5.5 其他 API

本节总结了本规范中未提及的其他 libfabric API 集的要求。表 2-27 列出了不需要支持的 libfabric API。

表 2-28 显示了不需要支持的 libfabric API 选项(例如标志、操作、参数等)。

2.2.5.6 Libfabric API 错误代码

SES 规范描述了一组广泛的错误代码。部分语义错误可能导致相关 libfabric API 函数通过 fi_cq_err_entry 数据结构出现完成错误。对于导致完成错误的语义错误,fi_cq_err_entry 结构的 err 字段必须填充相应的错误代码。如果未找到与语义错误对应的 libfabric 错误代码,则必须返回 FI_EIO 错误代码。此外,当发生语义完成错误时,提供程序必须将语义错误代码填充到 fi_cq_err_entry 结构的 prov_errno 字段中。

2.2.6 数据包传送模式

本节规定了如何选择 UET 数据包传送模式。 FI_EP_DGRAM 类型的 Libfabric 端点必须使用 UET UUD 数据包传送模式。 FI_EP_RDM 类型的 Libfabric 端点必须使用以下 UET 数据包传送模式之一:

• RUD(所有配置文件均支持)

• ROD(所有配置文件均支持)

• RUDI(HPC 配置文件支持)

AI Base 和 AI Full 配置文件必须选择 ROD 或 RUD。具体选择取决于操作类型和配置的消息排序模式。 为了明确选择标准,定义了以下消息排序模式:

• 当配置了以下任何一种消息排序模式时,发送消息排序有效(发送消息排序是指任何指定发送操作相对于其他操作的排序模式): o FI_ORDER_RAS、FI_ORDER_SAR、FI_ORDER_SAS、FI_ORDER_SAW、FI_ORDER_WAS

• 当配置了以下任何一种消息排序模式时,读/写消息排序有效(读/写消息排序是指任何指定读写操作相对于其他操作的排序模式): o FI_ORDER_ATOMIC_RAR、FI_ORDER_ATOMIC_RAW、FI_ORDER_ATOMIC_WAR、 FI_ORDER_ATOMIC_WAW、FI_ORDER_RAR、FI_ORDER_RAS FI_ORDER_RAW, FI_ORDER_RMA_RAR, FI_ORDER_RMA_RAW, FI_ORDER_RMA_WAR, FI_ORDER_RMA_WAW, FI_ORDER_SAR, FI_ORDER_SAW, FI_ORDER_WAR, FI_ORDER_WAS AI 基本配置文件必须根据表 2-29 选择数据包传送模式。

AI Full 配置文件必须根据表 2-30 选择数据包传送模式。

HPC 配置文件必须选择 ROD、RUD 或 RUDI。选择取决于操作类型、配置的消息排序模式以及供应商特定的策略。HPC 配置文件必须根据表 2-31 选择数据包传送模式。在显示 RUD/RUDI 的情况下,应根据供应商特定的策略选择使用 RUD 还是 RUDI。

2.2.7 流量类别

SES 子层仅识别数据流量类别。libfabric 应用程序无法识别 PDS 使用的流量类别。默认值如表 2-32 所示。UET 的其他子层使用附加流量类别及其关联的 DSCP 值,用于 libfabric 提供程序不可见的服务。这些流量类别通过特定于操作系统的方式(例如 Linux TC)配置,并且应在整个网络中保持一致。

可以通过设置表 2-7 中定义的 UET_PROVIDER_DEF_DATA_TC 配置参数来覆盖默认流量类别。libfabric 应用程序使用 struct fi_domain_attr 的 tclass 字段来控制数据流量类别。tclass 字段的值指示数据流量类别应使用默认流量类别还是表 2-4 中指定的特定 DSCP。

2.2.8 发送和接收队列

libfabric 数据传输操作通常通过一组由 NIC 硬件访问的发送和接收队列来实现。本节提供有关发送和接收队列操作特性的要求和指导,旨在促进通用的 NIC 行为以及对该行为的相关集体理解,从而简化性能调优。发送和接收队列操作的细节因供应商而异。

2.2.8.1 传输队列

传输队列用于在网络上发起传输的 libfabric API(例如 fi_send()、fi_tsend()、fi_write()、fi_read() 等)。传输队列包含工作元素,这些工作元素描述要执行的操作并标识关联的数据缓冲区。提供程序将工作元素插入传输队列,网卡硬件从传输队列中移除工作元素。当网卡硬件移除工作元素时,它会执行相关的网络传输。在最简单的情况下,可以使用单个传输队列来发起所有网络传输。但是,由于队头阻塞问题以及缺乏对具有不同传输特性的多种流量类别的支持,使用单个传输队列可能无法实现最佳性能。图 2-11 显示了传输队列配置示例。

UET 提供程序应支持多个传输队列。 UET 提供程序应支持将一个流量类别映射到一个或多个传输队列,以便不同的流量类别可以映射到不同的传输队列集。 UET 提供程序应将与特定流量类别(例如 TCa)相关的无序消息操作分布到配置为服务该流量类别(例如 TCa)的传输队列集。 当 libfabric 端点配置为消息排序时,UET 提供程序必须将该端点的操作限制在单个传输队列中。libfabric 消息排序模式已在 2.2.6 节中讨论过。

2.2.8.2 接收队列和注册内存区域

接收队列用于 libfabric API,这些 API 会发布用于从网络接收消息的缓冲区(例如 fi_recv()、fi_trecv() 等)。接收队列包含用于标识关联数据缓冲区及其属性(例如标签)的元素。提供程序将元素插入接收队列,网卡硬件则从接收队列中移除元素。当网卡硬件移除元素时,它会将从网络接收的消息数据存储在关联的数据缓冲区中。

在 libfabric 提供程序中注册的内存区域类似于接收队列,因为它们标识用作目标网络操作的缓冲区。已注册的内存区域可以作为远程 RMA 操作的目标。图 2-12 展示了与 libfabric 端点关联的接收队列和已注册内存区域的数据结构示例。在该示例中:

• 为未标记消息和标记消息分配单独的接收队列。

• 使用一个表来管理已注册的内存区域。该表包含用于标识关联数据缓冲区和属性(例如访问权限)的描述符。

支持标记消息的 UET 提供程序应在 libfabric 端点基础上为未标记消息和标记消息分配独立的接收队列。

2.2.9 安全协议

本节专门介绍提供程序对可选 UET 安全协议的支持。安全协议支持由与提供程序关联的内核驱动程序以对 libfabric API 透明的方式在后台实现。打开 libfabric 端点时,提供程序内核驱动程序将接收安全绑定参数,作为 UET 地址分配过程的一部分,该过程在 2.2.5.3.5.1 节中描述。安全绑定参数在表 2-33 中指定。实现 UET 安全协议的 UET 提供程序必须支持表 2-33 中指定的安全绑定参数。

实现 UET 安全协议的内核驱动程序还必须支持使用表 2-34 中指定的密钥更新参数进行密钥更新。

密钥更新参数可以由内核驱动程序请求,也可以由密钥管理系统推送。获取密钥更新参数的架构如图 2-13 所示。

图 2-13 所示的步骤如下:

  1. UET 提供程序内核驱动程序通过 UET 控制 API 向特权用户进程发出密钥更新请求。
  2. 特权用户进程与密钥管理系统通信并返回请求的密钥更新信息。
  3. 提供程序内核驱动程序将密钥参数编程到网卡硬件中。与此架构相关的要求如下:

• UET 提供程序内核驱动程序必须支持使用 UET 控制 API 向特权用户进程发送密钥更新请求。

• 特权用户进程必须使用密钥更新参数响应提供程序内核驱动程序的密钥更新请求。

• 提供程序内核驱动程序必须接受从特权用户进程收到的请求的和未经请求的密钥更新参数,并且必须将密钥参数编程到网卡硬件中。

提供程序内核驱动程序必须在密钥更新请求中包含表 2-35 中指定的参数。

UET安全绑定参数、密钥更新参数和密钥更新请求参数的“C”结构表示如图2-14所示。

2.2.10 有线协议映射

本节详细说明了 libfabric API 及相关数据结构如何映射到以下有线协议头中的字段:

• IP 头

• UET TSS 头

• UET PDS 头

• UET SES 头

图 2-15 为 libfabric 映射到 UET 有线协议头的高级描述。

2.2.10.1 IP 报头字段映射

libfabric 到 IP 报头字段的映射如表 2-36 所示。

2.2.10.2 UET TSS 字段映射

TSS 报头字段的生成基于来自提供程序内核驱动程序的安全绑定和来自 libfabric 的数据包信息。安全绑定在 libfabric 端点打开时初始化,并在密钥更新时刷新。来自 libfabric 的数据包信息包括 libfabric 域标识符和 FEP 的源 IP 地址。域标识符用于查找应应用的安全绑定参数,而源 IP 地址则由密钥派生函数使用。

2.2.10.3 UET PDS 报头字段映射

PDS 报头根据数据包传送模式而有所不同。UUD 和 RUDI 数据包传送模式不使用数据包传送上下文,并且 PDS 报头较小。对于 RUD 和 ROD 传送模式,libfabric 到 PDS 报头字段的映射主要是一种间接映射,其中 libfabric 数据用于选择 PDC,然后 PDC 状态决定 PDS 报头字段的内容。用于选择 PDC 的 libfabric 字段如表 2-37 所示

2.2.10.4 UET SES 报头字段映射

SES 规范描述了多种报头格式,如表 2-38 所示。

SES 标准请求标头的 libfabric 映射如表 2-39 所示。

2.2.5.3.4.1 节规定了使用优化的不匹配 SES 头进行 RMA 操作的标准。原子操作也必须遵循相同的标准。优化的不匹配 SES 头应该仅用于满足指定标准的 RMA 或原子操作。表 2-40 显示了优化的不匹配 SES 头的 libfabric 映射。

单一格式的小消息/小 RMA 支持多种用例。小消息用例的标准在表 2-41 中指定。当满足表 2-41 中指定的标准时,应使用小消息 SES 报头。

小消息 SES 标头的 libfabric 映射如表 2-42 所示。

小型 RMA 用例的标准和要求在第 2.2.5.3.4.1 节中指定。原子操作必须应用相同的标准。小型 RMA SES 标头应该用于满足指定标准的 RMA 或原子操作。小型 RMA SES 标头的 libfabric 映射如表 2-43 所示。

可延迟发送操作的使用标准和要求在第 2.2.5.4 节中指定。可延迟发送 SES 标头格式与标准标头类似,但 ses.buffer_offset 字段被提供商提供的 ses.initiator_restart_token 和 ses.target_restart_token 字段取代。可延迟发送序列中的“准备重启 (RTR)”消息也包含 ses.iniator_restart_token 和 ses.target_restart_token 字段。重启令牌用于标识正在重启的操作。提供商必须确保所有活动的重启令牌在发起 FEP 处都是唯一的。会合发送操作的使用标准和要求在第 2.2.5.4 节中指定。表 2-44 显示了会合发送扩展标头(位于标准标头之后)的 libfabric 映射。

原子扩展头与 fi_atomic() API 结合使用,并且可以遵循标准头或任一优化头。原子扩展头包含 ses.atomic_opcode 字段和 ses.atomic_datatype 字段。UET 提供程序必须将 fi_atomic() API 中指定的原子操作和原子数据类型映射到关联的 SES 头原子助记符,这些助记符在 UET SES 规范中定义。比较和交换扩展头是用于比较和交换原子操作的专用头。除了 ses.atomic_opcode 和 ses.atomic_datatype 字段外,该扩展还包含来自关联 fi_compare_atomic() API 的比较值和交换值参数。这些参数分别映射到 ses.compare_value 和 ses.swap_value 字段。比较和交换参数的大小必须小于等于 16 字节。

2.2.11 UET 控制 API 的 Linux 实现

本节描述的 UET 控制 API 的 Linux 实现是向上游社区提出的提案。预计变更和反馈将作为上游流程的一部分纳入其中。接口的最终位置将位于 Linux 包含文件中。本规范先前已定义了提供商 KMD 和管理实体之间的多个 UET 控制 API 消息。更具体地说,以下内容:

• UET 控制 API JobID 映射请求消息(参见 2.2.4.1 节)

• UET 控制 API 地址分配请求消息(参见 2.2.5.3.5.1 节)

• UET 控制 API 地址分配响应消息(参见 2.2.5.3.5.1 节)

• UET 控制 API 安全密钥更新消息(参见 2.2.9 节)

• UET 控制 API 安全密钥更新请求消息(参见 2.2.9 节)

在 Linux 实现中,UET 控制 API 必须使用 Netlink 消息实现。所有 Netlink 消息都使用新的“UET”系列与 UET 提供程序内核驱动程序进行交换。代表每条消息的 Netlink 命令的基本编码集如图 2-16 所示。

为了便于扩展,Netlink 不再将消息表示为“C”结构,而是使用一系列类型属性。用于表示 UET Netlink 消息的基本属性集如图 2-17 所示。

2.2.12 参考文献

[1] IETF RFC 2474,“IPv4 和 IPv6 报头中差异服务字段(DS 字段)的定义”,1998 年。[在线]。可访问:https://datatracker.ietf.org/doc/html/rfc2474。 [2] IETF RFC 3246,“快速转发 PHB(单跳行为)”,2002 年。[在线]。可访问:https://datatracker.ietf.org/doc/html/rfc3246

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.2 UE Libfabric 映射
    • 2.2.1 应用用例
    • 2.2.2 UET 配置文件
      • 2.2.2.1 配置文件协商和配置文件间互操作性
    • 2.2.3 配置信息
    • 2.2.4 JobID
      • 2.2.4.1 在作业初始化时分配 JobID
      • 2.2.4.2 备用 JobID 分配
      • 2.2.4.3 授权
      • 2.2.4.4 数据传输操作的 JobID 选择
    • 2.2.5 Libfabric API
      • 2.2.5.1 Libfabric 寻址
      • 2.2.5.2 发现 API
      • 2.2.5.3 通信和完成 API
      • 2.2.5.4 OFI 数据传输 API
      • 2.2.5.5 其他 API
      • 2.2.5.6 Libfabric API 错误代码
    • 2.2.6 数据包传送模式
    • 2.2.7 流量类别
    • 2.2.8 发送和接收队列
      • 2.2.8.1 传输队列
      • 2.2.8.2 接收队列和注册内存区域
    • 2.2.9 安全协议
    • 2.2.10 有线协议映射
      • 2.2.10.1 IP 报头字段映射
      • 2.2.10.2 UET TSS 字段映射
      • 2.2.10.3 UET PDS 报头字段映射
      • 2.2.10.4 UET SES 报头字段映射
    • 2.2.11 UET 控制 API 的 Linux 实现
    • 2.2.12 参考文献
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档