DOCA 文档 v2.10.0

DOCA 存储零拷贝发起端 Comch 应用程序指南

DOCA 存储零拷贝发起端 Comch 应用程序 (initiator_comch) 扮演以下角色

  1. 演示如何使用 DOCA Comch API (客户端-服务器) 在 x86 主机和 BlueField 之间通信配置

  2. 演示如何使用 DOCA Comch API (生产者-消费者) 和硬件加速来卸载数据路径中 x86 主机和 BlueField 之间高效的消息传输。

  3. 为这种应用程序/用例的性能提供基准。

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 消息将引用单个导出内存区域的不同段。 确保每个线程使用导出的内存的单独区域消除了多线程访问内存的复杂性。 如果需要,用户可以选择扩展应用程序以支持多个唯一的内存区域,以便每个线程都有一个。

initiator_system_design-version-1-modificationdate-1734470117590-api-v2.png

DOCA 存储零拷贝发起端分三个阶段执行

  1. 准备.

  2. 数据路径.

  3. 拆卸.

准备阶段

在此阶段,应用程序执行以下操作

  1. 为控制路径分配所需的 DOCA 对象和内存。

  2. 创建 DOCA Comch 客户端并连接到 comch_to_rdma。

  3. 向 comch_to_rdma 发送“配置数据路径”控制消息(缓冲区计数、缓冲区大小、doca_mmap 导出详细信息)。

  4. 等待来自 comch_to_rdma 的配置数据路径控制消息响应。

  5. 创建数据路径对象。

  6. 向 comch_to_rdma 发送“启动数据路径连接”控制消息。

  7. 等待来自 comch_to_rdma 的“启动数据路径”控制消息响应。

  8. 使用必要的数据填充所有 IO 消息。

  9. 向 comch_to_rdma 发送“启动存储”控制消息。

  10. 等待来自 comch_to_rdma 的启动存储控制消息响应。

initiator_preperation_stage-version-1-modificationdate-1734470117210-api-v2.png

数据路径阶段

数据路径状态既作为示例,又作为内置基准,并且仅使用数据路径对象。 此阶段不使用控制路径对象或代码。

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

initiator_data_path_stage-version-1-modificationdate-1734470116830-api-v2.png

拆卸阶段

要拆卸,应用程序执行以下操作

  1. 显示执行统计信息。

  2. 向 comch_to_rdma 发送“销毁对象”控制消息。

  3. 等待来自 comch_to_rdma 的销毁对象控制消息响应。

  4. 销毁数据路径对象。

  5. 销毁控制路径对象。

  6. 销毁任何其他分配的内存/对象。

此应用程序利用以下 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 level for 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 wait while performing control operations. Default: 10   --batch-size                      Batch size: Default: ${per-cpu-buffer-count} / 2

    信息

    此用法打印输出可以使用 -h (或 --help) 选项打印到命令行

    复制
    已复制!
                

    ./doca_storage_zero_copy_initiator_comch -h

    有关更多信息,请参阅“命令行标志”部分。

  • 在主机上运行应用程序的 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 内容

通用标志

h

help

打印帮助概要

N/A

v

version

打印程序版本信息

N/A

l

log-level

设置应用程序的日志级别

  • DISABLE=10

  • CRITICAL=20

  • ERROR=30

  • WARNING=40

  • INFO=50

  • DEBUG=60

  • TRACE=70 (需要使用 TRACE 日志级别支持进行编译)

复制
已复制!
            

"log-level": 60

N/A

sdk-log-level

设置程序的日志级别

  • DISABLE=10

  • CRITICAL=20

  • ERROR=30

  • WARNING=40

  • INFO=50

  • DEBUG=60

  • TRACE=70

复制
已复制!
            

"sdk-log-level": 40

j

json

从输入 JSON 文件解析所有命令标志

N/A

程序标志

d

device

DOCA 设备标识符。 以下之一

  • PCIe 地址: 3b:00.0

  • InfiniBand 名称: mlx5_0

  • 网络接口名称: en3f0pf0sf0

注意

此标志是强制性的。

复制
已复制!
            

"device": "3b:00.0"

N/A

operation

要执行的操作,可以是 readwrite

注意

此标志是强制性的。

复制
已复制!
            

"operation": "read"

N/A

--run-limit-operation-count

运行 N 次操作(事务)然后停止

注意

此标志是强制性的。

复制
已复制!
            

"run-limit-operation-count": 10000000

N/A

--cpu

要使用的 CPU 索引。 每个 CPU 产生一个数据路径线程。 索引从 0 开始。

注意

用户可以多次指定此参数以创建更多线程。

注意

此标志是强制性的。

复制
已复制!
            

"cpu": 6

N/A

--per-cpu-buffer-count

每个 CPU 要使用的缓冲区数量(所有缓冲区并行执行)

复制
已复制!
            

"per-cpu-buffer-count": 64

N/A

--buffer-size

用于数据传输的缓冲区大小。 应该是代表磁盘块大小的值。

复制
已复制!
            

"buffer-size": 4096

N/A

--validate-writes

运行功能测试而不是性能测试。 仅与写入操作模式兼容。

复制
已复制!
            

"validate-writes": true

N/A

--command-channel-name

如果同一设备上存在多个 comch 服务器,则允许自定义用于此应用程序实例的服务器名称

复制
已复制!
            

"command-channel-name": "storage_zero_copy_comch"

N/A

--control-timeout

控制操作完成的超时时间(秒)。 如果任何控制操作超过此时间,应用程序将中止。

复制
已复制!
            

"control-timeout": 10

N/A

--batch-size

使用批量 API 提交任务时要使用的批处理大小

复制
已复制!
            

"batch-size": 8


故障排除

有关 DOCA 应用程序的安装或执行中遇到的任何问题,请参阅 DOCA 故障排除

控制线程流程

  1. 解析应用程序参数

    复制
    已复制!
                

    auto const cfg = parse_cli_args(argc, argv);

    1. 准备解析器 (doca_argp_init)。

    2. 注册参数 (doca_argp_param_create)。

    3. 解析参数 (doca_argp_start)。

    4. 销毁解析器 (doca_argp_destroy)。

  2. 显示配置

    复制
    已复制!
                

    print_config(cfg);

  3. 创建应用程序实例

    复制
    已复制!
                

    g_app.reset(storage::zero_copy::make_host_application(cfg));

  4. 运行应用程序

    复制
    已复制!
                

    g_app->run()

    1. 查找并打开指定的设备

      复制
      已复制!
                  

      m_dev = storage::common::open_device(m_cfg.device_id);

    2. 创建控制路径进度引擎

      复制
      已复制!
                  

      doca_pe_create(&m_ctrl_pe);

    3. 创建 comch 控制对象

      复制
      已复制!
                  

      create_comch_control();

    4. 连接到 comch 服务器

      复制
      已复制!
                  

      connect_comch_control();

    5. 配置存储

      复制
      已复制!
                  

      configure_storage();

      1. 分配本地内存区域。

      2. 创建 doca_mmap。

      3. 向 comch_to_rdma 发送配置数据路径控制消息。

      4. 等待来自 comch_to_rdma 的配置数据路径控制消息响应。

    6. 准备数据路径

      复制
      已复制!
                  

      prepare_data_path();

      1. 创建每个线程的数据上下文

        1. 创建 IO 消息。

        2. 创建事务对象。

        3. 创建进度引擎。

        4. 为 IO 消息缓冲区创建 mmap。

        5. 创建 Comch 生产者。

        6. 创建 Comch 消费者。

      2. 向 comch_to_rdma 发送启动数据路径连接控制消息。

      3. 等待来自 comch_to_rdma 的启动数据路径连接控制消息响应。

      4. 轮询进度引擎直到

        1. 已收到远程消费者 ID 值。

        2. 所有消费者都在运行。

        3. 所有生产者都在运行。

    7. 创建任务

      复制
      已复制!
                  

      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);

    8. 创建线程

      复制
      已复制!
                  

      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)}; } }

    9. 启动数据路径

      复制
      已复制!
                  

      wait_for_control_response(send_control_message(control_message_type::start_storage));

    10. 记录开始时间。

    11. 提交初始 DOCA Comch 消费者任务。

    12. 启动数据路径线程。

    13. 等待所有线程完成。

    14. 记录结束时间。

    15. 停止存储。

    16. 关闭。

  5. 显示统计信息

    复制
    已复制!
                

    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");

性能数据路径线程流程

  1. 启动事务

    复制
    已复制!
                

    for (uint32_t ii = 0; ii != transactions_size; ++ii) start_transaction(transactions[ii], std::chrono::steady_clock::now());

  2. 运行直到 N 次操作已完成

    复制
    已复制!
                

    while (run_flag) { doca_pe_progress(data_pe) ? ++(pe_hit_count) : ++(pe_miss_count); }

功能数据路径线程流程

  1. 确定要执行的迭代次数(每次迭代最多为 --per-cpu-buffer-count 事务)

    复制
    已复制!
                

    uint32_t const iteration_count = (remaining_tx_ops / transactions_size) + ((remaining_tx_ops % transactions_size) == 0 ? 0 : 1);

  2. 对于每次迭代

    1. 将本地内存区域中的数据设置为固定模式。

    2. 将所有事务设置为写入模式

      复制
      已复制!
                  

      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))); } }

    3. 启动所有事务。

    4. 轮询 PE 直到所有事务完成。

    5. 将本地内存区域中的数据设置为备用固定模式。

    6. 将所有事务设置为读取模式。

    7. 启动所有事务。

    8. 轮询 PE 直到所有事务完成。

    9. 验证本地内存区域中的所有数据都已修改,并反映原始数据模式而不是备用模式。

  • /opt/mellanox/doca/applications/storage/

© 版权所有 2025, NVIDIA。 上次更新日期:2025 年 2 月 12 日。