DOCA 存储零拷贝发起端 Comch 应用程序指南
DOCA 存储零拷贝发起端 Comch 应用程序 (initiator_comch) 扮演以下角色
演示如何使用 DOCA Comch API (客户端-服务器) 在 x86 主机和 BlueField 之间通信配置
演示如何使用 DOCA Comch API (生产者-消费者) 和硬件加速来卸载数据路径中 x86 主机和 BlueField 之间高效的消息传输。
为这种应用程序/用例的性能提供基准。
DOCA 存储零拷贝发起端 Comch 应用程序创建一个本地内存区域和一组消息缓冲区,以指示 doca_storage_zero_copy_comch_to_rdma
(comch_to_rdma) 应用程序对创建的本地内存区域执行读写操作。 initiator_comch 应用程序负责向 comch_to_rdma 提供内存区域详细信息和访问详细信息。 initiator_comch 应用程序不了解 doca_storage_zero_copy_target_rdma
(target_rdma) 应用程序的具体细节,也不直接参与执行 RDMA 操作以影响与 target_rdma 之间的数据传输所需的动作。
数据路径对象是每个线程创建的,为了保持简单性,使用单个内存区域,并且每个线程及其 IO 消息将引用单个导出内存区域的不同段。 确保每个线程使用导出的内存的单独区域消除了多线程访问内存的复杂性。 如果需要,用户可以选择扩展应用程序以支持多个唯一的内存区域,以便每个线程都有一个。

DOCA 存储零拷贝发起端分三个阶段执行
准备阶段
在此阶段,应用程序执行以下操作
为控制路径分配所需的 DOCA 对象和内存。
创建 DOCA Comch 客户端并连接到 comch_to_rdma。
向 comch_to_rdma 发送“配置数据路径”控制消息(缓冲区计数、缓冲区大小、doca_mmap 导出详细信息)。
等待来自 comch_to_rdma 的配置数据路径控制消息响应。
创建数据路径对象。
向 comch_to_rdma 发送“启动数据路径连接”控制消息。
等待来自 comch_to_rdma 的“启动数据路径”控制消息响应。
使用必要的数据填充所有 IO 消息。
向 comch_to_rdma 发送“启动存储”控制消息。
等待来自 comch_to_rdma 的启动存储控制消息响应。

数据路径阶段
数据路径状态既作为示例,又作为内置基准,并且仅使用数据路径对象。 此阶段不使用控制路径对象或代码。
基准测试首先尽可能快地提交所有任务以启动所有事务,然后尽可能快地轮询 进度引擎 (PE)。 每个线程执行相同的数据路径功能。 随着每个任务完成,它会递减事务引用计数。 一旦此值达到 0,事务就可以再次启动。 这是必需的,因为 DOCA Comch 生产者和消费者事件回调之间没有时间保证。 可能在收到生产者发送完成通知之前收到消费者完成通知。 一旦线程完成其所需的事务数(总事务运行限制,由 --run-limit-operation-count
除以线程数指定),该线程就会退出。 一旦所有线程都加入,应用程序将继续发送停止 IO 消息并进入拆卸阶段。

拆卸阶段
要拆卸,应用程序执行以下操作
显示执行统计信息。
向 comch_to_rdma 发送“销毁对象”控制消息。
等待来自 comch_to_rdma 的销毁对象控制消息响应。
销毁数据路径对象。
销毁控制路径对象。
销毁任何其他分配的内存/对象。
此应用程序利用以下 DOCA 库
此应用程序作为存储零拷贝应用程序集的一部分进行编译。 有关编译说明,请参阅 NVIDIA DOCA 存储零拷贝。
应用程序执行
此应用程序只能在主机上运行。
DOCA 存储零拷贝发起端以源代码形式提供。 因此,在执行应用程序之前需要进行编译。
应用程序使用说明
Usage: doca_storage_zero_copy_initiator_comch [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 --operation Operation to perform. One of: read|write --run-limit-operation-count Run N operations then stop --cpu CPU core to which the process affinity can be set --per-cpu-buffer-count Number of memory buffers to create. Default:64
--buffer-size Size of each created buffer. Default:4096
--validate-writes Enable validation of writes operations by reading them back afterwards. Default:false
--command-channel-name Name of the channel used by the doca_comch_client. Default: storage_zero_copy_comch --control-timeout Time (in seconds) to waitwhile
performing control operations. Default:10
--batch-size Batch size: Default: ${per-cpu-buffer-count} /2
信息在主机上运行应用程序的 CLI 示例
./doca_storage_zero_copy_initiator_comch -d 3b:00.0 --operation read --run-limit-operation-count 10000000 --cpu 5
信息DOCA 设备 PCIe 地址
3b:00.0
应与所需 PCIe 设备的地址匹配。该应用程序还支持基于 JSON 的部署模式,其中所有命令行参数都通过 JSON 文件提供
./doca_storage_zero_copy_initiator_comch --json [json_file]
例如
./doca_storage_zero_copy_initiator_comch --json doca_storage_reference_zero_copy_host_params.json
注意在执行之前,请确保使用的 JSON 文件包含正确的配置参数,尤其是部署所需的 PCIe 地址。
命令行标志
标志类型 | 短标志 | 长标志/JSON 键 | 描述 | JSON 内容 |
通用标志 |
|
| 打印帮助概要 | N/A |
|
| 打印程序版本信息 | N/A | |
|
| 设置应用程序的日志级别
|
| |
N/A |
| 设置程序的日志级别
|
| |
|
| 从输入 JSON 文件解析所有命令标志 | N/A | |
程序标志 |
|
| DOCA 设备标识符。 以下之一
注意
此标志是强制性的。
|
|
N/A |
| 要执行的操作,可以是 注意
此标志是强制性的。 |
| |
N/A |
| 运行 注意
此标志是强制性的。 |
| |
N/A |
| 要使用的 CPU 索引。 每个 CPU 产生一个数据路径线程。 索引从 0 开始。 注意
用户可以多次指定此参数以创建更多线程。
注意
此标志是强制性的。 |
| |
N/A |
| 每个 CPU 要使用的缓冲区数量(所有缓冲区并行执行) |
| |
N/A |
| 用于数据传输的缓冲区大小。 应该是代表磁盘块大小的值。 |
| |
N/A |
| 运行功能测试而不是性能测试。 仅与写入操作模式兼容。 |
| |
N/A |
| 如果同一设备上存在多个 comch 服务器,则允许自定义用于此应用程序实例的服务器名称 |
| |
N/A |
| 控制操作完成的超时时间(秒)。 如果任何控制操作超过此时间,应用程序将中止。 |
| |
N/A |
| 使用批量 API 提交任务时要使用的批处理大小 |
|
故障排除
有关 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_host_application(cfg));
运行应用程序
g_app->run()
查找并打开指定的设备
m_dev = storage::common::open_device(m_cfg.device_id);
创建控制路径进度引擎
doca_pe_create(&m_ctrl_pe);
创建 comch 控制对象
create_comch_control();
连接到 comch 服务器
connect_comch_control();
配置存储
configure_storage();
分配本地内存区域。
创建 doca_mmap。
向 comch_to_rdma 发送配置数据路径控制消息。
等待来自 comch_to_rdma 的配置数据路径控制消息响应。
准备数据路径
prepare_data_path();
创建每个线程的数据上下文
创建 IO 消息。
创建事务对象。
创建进度引擎。
为 IO 消息缓冲区创建 mmap。
创建 Comch 生产者。
创建 Comch 消费者。
向 comch_to_rdma 发送启动数据路径连接控制消息。
等待来自 comch_to_rdma 的启动数据路径连接控制消息响应。
轮询进度引擎直到
已收到远程消费者 ID 值。
所有消费者都在运行。
所有生产者都在运行。
创建任务
m_thread_contexts[ii].create_tasks(m_raw_io_data + (ii * per_thread_task_count * m_cfg.buffer_size), m_cfg.buffer_size, m_remote_consumer_ids[ii], op_type, m_cfg.batch_size);
创建线程
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)}; } }启动数据路径
wait_for_control_response(send_control_message(control_message_type::start_storage));
记录开始时间。
提交初始 DOCA Comch 消费者任务。
启动数据路径线程。
等待所有线程完成。
记录结束时间。
停止存储。
关闭。
显示统计信息
printf
("+================================================+\n"
);printf
("| Stats\n"
);printf
("+================================================+\n"
);printf
("| Duration (seconds): %2.06lf\n"
, duration_secs_float);printf
("| Operation count: %u\n"
, stats.operation_count);printf
("| Data rate: %.03lf GiB/s\n"
, GiBs / duration_secs_float);printf
("| IO rate: %.03lf MIOP/s\n"
, miops);printf
("| PE hit rate: %2.03lf%% (%lu:%lu)\n"
, pe_hit_rate_pct, stats.pe_hit_count, stats.pe_miss_count);printf
("| Latency:\n"
);printf
("| \tMin: %uus\n"
, stats.latency_min);printf
("| \tMax: %uus\n"
, stats.latency_max);printf
("| \tMean: %uus\n"
, stats.latency_mean);printf
("+================================================+\n"
);
性能数据路径线程流程
启动事务
for
(uint32_t ii = 0; ii != transactions_size; ++ii) start_transaction(transactions[ii], std::chrono::steady_clock::now());运行直到
N
次操作已完成while
(run_flag) { doca_pe_progress(data_pe) ? ++(pe_hit_count) : ++(pe_miss_count); }
功能数据路径线程流程
确定要执行的迭代次数(每次迭代最多为
--per-cpu-buffer-count
事务)uint32_t
const
iteration_count = (remaining_tx_ops / transactions_size) + ((remaining_tx_ops % transactions_size) == 0 ? 0 : 1);对于每次迭代
将本地内存区域中的数据设置为固定模式。
将所有事务设置为写入模式
void
thread_hot_data::set_operation(io_message_type operation) {for
(uint32_t ii = 0; ii != transactions_size; ++ii) { auto *io_message =const_cast
<char
*>(storage::common::get_buffer_bytes( doca_comch_producer_task_send_get_buf(transactions[ii].request))); } }启动所有事务。
轮询 PE 直到所有事务完成。
将本地内存区域中的数据设置为备用固定模式。
将所有事务设置为读取模式。
启动所有事务。
轮询 PE 直到所有事务完成。
验证本地内存区域中的所有数据都已修改,并反映原始数据模式而不是备用模式。
/opt/mellanox/doca/applications/storage/