DOCA 存储零拷贝 Comch 到 RDMA 应用程序指南
DOCA 存储零拷贝 Comch 到 RDMA (comch_to_rdma) 是 doca_storage_zero_copy_initiator_comch
(initiator_comch) 和 doca_storage_zero_copy_target_rdma
(target_rdma) 之间的通信桥梁。这使 initiator_comch 免受 target_rdma 细节的影响。
Comch_to_rdma 通过 TCP 连接到 target_rdma。
Comch_to_rdma 创建一个 comch 服务器并等待 initiator_comch 连接。
Comch_to_rdma 等待来自 initiator_comch 的控制消息并对其做出适当的反应。
信息每个线程建立两个 RDMA 连接,以避免大型 RDMA 数据传输干扰或延迟较小的 IO 消息。

DOCA 存储零拷贝 Comch 到 RDMA 分三个阶段执行
准备阶段
在此阶段,应用程序执行以下操作
通过 TCP 连接到 target_rdma。
创建一个 DOCA Comch 服务器并等待客户端连接。
等待来自 initiator_comch 的“配置数据路径”控制消息(包括缓冲区计数、缓冲区大小、doca_mmap 导出详细信息)。
使用来自 initiator_comch 的导出详细信息创建 doca_mmap,然后重新导出它以提供对 target_rdma 的访问。
向 target_rdma 发送配置数据路径控制消息。
等待来自 target_rdma 的配置数据路径控制消息响应,状态为成功。
向 initiator_comch 发送配置数据路径控制消息响应。
等待来自 initiator_comch 的“启动数据路径连接”控制消息。
创建 comch 数据路径对象。
创建
N
个 RDMA 连接,与 target_rdma 交换连接详细信息。将启动数据路径连接控制消息中继到 target_rdma。
等待来自 target_rdma 的启动数据路径连接控制消息响应,状态为成功。
向 initiator_comch 发送启动数据路径连接控制消息响应。
等待来自 initiator_comch 的“启动存储”控制消息。
验证所有 RDMA 和 Comch 连接是否准备就绪可以使用。
向 target_rdma 发送启动存储控制消息。
等待来自 target_rdma 的启动存储控制消息响应,状态为成功。
启动数据路径线程。
向 initiator_comch 发送启动存储控制消息响应。

数据路径阶段
此阶段启动数据路径线程。每个线程首先提交接收 comch 和 RDMA 任务,然后执行一个紧密循环,尽可能快地轮询进度引擎 (PE),直到收到“数据路径停止”IO 消息。数据路径线程的工作是被动的,因此在任务完成回调中执行。当从 initiator_comch 接收到每个 IO 消息时,它将被转发到存储应用程序。同样,当从 target_rdma 接收到每个 IO 消息响应时,它将被中继回 initiator_comch。
拆卸阶段
在此阶段,应用程序执行以下操作
等待来自 initiator_comch 的销毁对象控制消息。
向 target_rdma 发送销毁对象控制消息。
等待来自 target_rdma 的销毁对象控制消息响应。
销毁数据路径对象。
向 initiator_comch 发送销毁对象控制消息响应。
销毁控制路径对象。
此应用程序利用以下 DOCA 库
此应用程序作为存储零拷贝应用程序集的一部分进行编译。有关编译说明,请参阅 NVIDIA DOCA 存储零拷贝。
应用程序执行
此应用程序只能在主机上运行。
DOCA 存储零拷贝 Comch 到 RDMA 以源代码形式提供。因此,在执行应用程序之前需要进行编译。
应用程序使用说明
Usage: doca_storage_zero_copy_comch_to_rdma [DOCA Flags] [Program Flags] DOCA Flags: -h, --help Print a help synopsis -v, --version Print program version information -l, --log-level Set the (numeric) log level
for
the program <10
=DISABLE,20
=CRITICAL,30
=ERROR,40
=WARNING,50
=INFO,60
=DEBUG,70
=TRACE> --sdk-log-level Set the SDK (numeric) log levelfor
the program <10
=DISABLE,20
=CRITICAL,30
=ERROR,40
=WARNING,50
=INFO,60
=DEBUG,70
=TRACE> -j, --json <path> Parse all command flags from an input json file Program Flags: -d, --device Device identifier -r, --representor Device host side representor identifier --cpu CPU core to which the process affinity can be set --storage-server One or more storage server addresses in <ip_addr>:<port> format --command-channel-name Name of the channel used by the doca_comch_server. Default: storage_zero_copy_comch信息在 BlueField 上运行应用程序的 CLI 示例
./doca_storage_zero_copy_comch_to_rdma -d 03:00.0 -r 3b:00.0 --storage-server 172.17.0.1:12345 --cpu 12
注意DOCA Comch 设备 PCIe 地址 (
03:00.0
) 和 DOCA Comch 设备表示器 PCIe 地址 (3b:00.0
) 都应与所需 PCIe 设备的地址匹配。该应用程序还支持基于 JSON 的部署模式,其中所有命令行参数都通过 JSON 文件提供
./doca_storage_zero_copy_comch_to_rdma --json [json_file]
例如
./doca_storage_zero_copy_comch_to_rdma --json doca_storage_zero_copy_comch_to_rdma_params.json
注意在执行之前,请确保使用的 JSON 文件包含正确的配置参数,尤其是部署所需的 PCIe 地址。
命令行标志
标志类型 | 短标志 | 长标志/JSON 键 | 描述 | JSON 内容 |
通用标志 |
|
| 打印帮助概要 | N/A |
|
| 打印程序版本信息 | N/A | |
|
| 设置应用程序的日志级别
|
| |
N/A |
| 设置程序的日志级别
|
| |
|
| 从输入 JSON 文件解析所有命令标志 | N/A | |
程序标志 |
|
| DOCA 设备标识符。以下之一
注意
此标志是强制性的。 |
|
|
| DOCA Comch 设备表示器 PCIe 地址 注意
此标志是强制性的。 |
| |
N/A |
| 要使用的 CPU 索引。每个 CPU 产生一个数据路径线程。索引从 0 开始。 注意
用户可以多次指定此参数以创建更多线程。
注意
此标志是强制性的。 |
| |
N/A |
| 用于建立与目标的控制 TCP 连接的 IP 地址和端口。 注意
此标志是强制性的。 |
| |
N/A |
| 如果同一设备上存在多个 comch 服务器,则允许自定义用于此应用程序实例的服务器名称。 |
|
故障排除
有关 DOCA 应用程序的安装或执行中遇到的任何问题,请参阅 DOCA 故障排除。
控制线程流程
解析应用程序参数
auto
const
cfg = parse_cli_args(argc, argv);准备解析器 (
doca_argp_init
)。注册参数 (
doca_argp_param_create
)。解析参数 (
doca_argp_start
)。销毁解析器 (
doca_argp_destroy
)。
显示配置
print_config(cfg);
创建应用程序实例
g_app.reset(storage::zero_copy::make_dpu_application(cfg));
运行应用程序
g_app->run()
查找并打开指定的设备
m_dev = storage::common::open_device(m_cfg.device_id);
查找并打开选定的表示器
m_dev_rep = storage::common::open_representor(m_dev, m_cfg.representor_id);
创建控制路径进度引擎
doca_pe_create(&m_ctrl_pe);
连接到 target_rdma
connect_storage_server();
创建 TCP 套接字。
连接 TCP 套接字。
创建 comch 服务器并等待 comch 客户端连接
create_comch_server();
while
(m_client_connection == nullptr) {static_cast
<void
>(doca_pe_progress(m_ctrl_pe));if
(m_abort_flag)return
; }等待配置存储控制消息。
配置存储
configure_storage();
使用 initiator_comch 提供的导出详细信息创建 mmap。
导出 mmap 以允许 RDMA 访问。
将“配置存储”控制消息与重新导出的 mmap 详细信息发送到 target_rdma。
等待来自 target_rdma 的配置存储控制消息响应。
向 initiator_comch 发送配置存储控制消息响应。
等待“启动数据路径”控制消息。
准备数据路径
for
(uint32_t ii = 0; ii != m_cfg.cpu_set.size(); ++ii) { prepare_storage_context(ii, msg.correlation_id); }创建每个线程的数据上下文
创建 IO 消息。
创建进度引擎。
为 IO 消息缓冲区创建 mmap。
创建 comch 生产者。
创建 comch 消费者。
创建 RDMA 上下文。
创建 RDMA 连接
导出 RDMA 连接详细信息 (
doca_rdma_export
)。发送“创建 RDMA 连接”控制消息。
等待创建 RDMA 连接控制消息。
使用远程 RDMA 连接详细信息
doca_rdma_connect
启动连接。
将数据路径控制消息发送到 target_rdma。
等待来自 target_rdma 的数据路径控制消息响应。
向 initiator_comch 发送数据路径控制消息响应。
等待启动存储控制消息。
验证所有连接是否准备就绪(comch 和 RDMA)
wait_for_connections_to_establish();
向 target_rdma 发送启动存储控制消息。
创建线程
if
(op_type == io_message_type::read) { m_thread_contexts[ii].thread
= std::thread
{&thread_hot_data::non_validated_test, std::addressof(m_thread_contexts[ii].hot_context)}; }else
if
(op_type == io_message_type::write) {if
(m_cfg.validate_writes) { m_thread_contexts[ii].thread
= std::thread
{&thread_hot_data::validated_test, std::addressof(m_thread_contexts[ii].hot_context)}; }else
{ m_thread_contexts[ii].thread
= std::thread
{&thread_hot_data::non_validated_test, std::addressof(m_thread_contexts[ii].hot_context)}; } }等待来自 target_rdma 的“启动存储”控制消息响应。
启动数据路径线程。
向 initiator_comch 发送启动存储控制消息响应。
运行所有线程直到完成。
等待“销毁对象”控制消息。
向 target_rdma 发送销毁对象控制消息。
等待来自 target_rdma 的销毁对象控制消息响应。
销毁数据路径对象。
向 initiator_comch 发送销毁对象控制消息响应。
显示统计信息
printf
("+================================================+\n"
);printf
("| Stats\n"
);printf
("+================================================+\n"
);for
(uint32_t ii = 0; ii != stats.size(); ++ii) {printf
("| Thread[%u]\n"
, ii); autoconst
pe_hit_rate_pct = (static_cast
<double
>(stats[ii].pe_hit_count) / (static_cast
<double
>(stats[ii].pe_hit_count) +static_cast
<double
>(stats[ii].pe_miss_count))) * 100.;printf
("| PE hit rate: %2.03lf%% (%lu:%lu)\n"
, pe_hit_rate_pct, stats[ii].pe_hit_count, stats[ii].pe_miss_count);printf
("+------------------------------------------------+\n"
); }printf
("+================================================+\n"
);销毁控制路径对象。
性能数据路径线程流程
数据路径涉及尽可能快地轮询 PE;以接收来自 initiator_comch 或 target_rdma 的 IO 消息。
运行直到 initiator_comch 发送停止 IO 消息
while
(hot_data->running_flag) { doca_pe_progress(pe) ? ++(hot_data->pe_hit_count) : ++(hot_data->pe_miss_count); }处理来自 initiator_comch 的 IO 消息
auto *
const
hot_data =static_cast
<thread_hot_data *>(ctx_user_data.ptr); ... doca_task_submit(static_cast
<doca_task *>(task_user_data.ptr));处理来自 target_rdma 的 IO 消息
auto *
const
hot_data =static_cast
<thread_hot_data *>(ctx_user_data.ptr); doca_error_t ret; auto *const
io_message = storage::common::get_buffer_bytes(doca_rdma_task_receive_get_dst_buf(task));if
(io_message_view::get_type(io_message) != io_message_type::stop) { io_message_view::set_type(io_message_type::result, io_message); io_message_view::set_result(DOCA_SUCCESS, io_message); }else
{ hot_data->app_impl->stop_all_threads(); }do
{ ret = doca_task_submit(static_cast
<doca_task *>(task_user_data.ptr)); }while
(ret == DOCA_ERROR_AGAIN);
/opt/mellanox/doca/applications/storage/