Tutti local-NVMe hardware contract tests
本文记录三个 CUDA userspace local-NVMe contract test 的运行方法。运行测试前,
必须先启动 tutti_daemon,并使用与 daemon 配置一致的设备参数。
1. 运行前提
1.1 构建测试
硬件测试由 TUTTI_BUILD_HARDWARE_TESTS 控制。首次配置或切换配置后执行:
cmake --preset cuda --fresh -DTUTTI_BUILD_HARDWARE_TESTS=ON
cmake --build --preset cuda --target \
tutti_local_nvme_datapath_contract_test \
tutti_storage_runtime_local_nvme_contract_test \
tutti_striped_local_nvme_contract_test --parallel 8
二进制位于 build/cuda/bin/。
1.2 启动 daemon
sudo env TUTTI_VERBOSE=1 \
build/cuda-module/bin/tutti_daemon \
--config config/local/daemon_2disk.yaml
1.3 将 daemon 配置转换为 --nvme
测试不会读取 YAML;通过 --nvme 显式传入设备表,格式为:
ssnvme_path,pci_bdf,backing_device,mount_path[,block_size[,bar0_size[,namespace_id]]]
字段依次为 daemon RPC 报告的 snvme、pci_addr、对应 namespace 块设备、真实
mount_path、blk、bar0 和 namespace_id。先运行 client 的 --list-only,
以 RPC metadata 为准生成参数;不要根据 YAML 数组顺序或设备名模板推导路径。
GPU view(例如 /mnt/snvme/gpu0/ssnvme0)不是 backing mount_path。
legacy allowed_gpus 必须包含测试命令的 --gpu。
当前 config/local/daemon_2disk.yaml 的一次实机 RPC 结果如下(两个 namespace 均为
4 KiB);daemon 每次 bring-up 后仍须重新核对这些 metadata:
NVME0='/dev/ssnvme0,0000:41:00.0,/dev/snvme0n1,/mnt/snvme/nvme1,4096,32768,1'
NVME1='/dev/ssnvme1,0000:44:00.0,/dev/snvme1n1,/mnt/snvme/nvme2,4096,32768,1'
如果 daemon 使用其他 YAML,必须同步修改这些字段。block_size 是 namespace
LBA 大小;Striped 测试选择的 namespace 必须一致。
2. Test
2.1 LocalNvmeDataPath contract
覆盖 LocalNvmeDataPath 生命周期、内存/DMA、SINGLE/DUAL/LIST I/O、错误处理、并发、 缓存和多设备场景:
build/cuda/bin/tutti_local_nvme_datapath_contract_test \
--gpu 0 \
--device-index 0 \
--nvme "$NVME0" \
--nvme "$NVME1"
重复 --nvme 会替换内置设备表(最多四项);--device-index 选择 primary entry。
Queue pair 要求
测试中的生产 LocalNvmeDataPath 固定请求 kNumQueues=16,因此每个使用的
controller 需要 user_io_qps >= 16 且 max_q_per_grp >= 16。
2.2 StorageRuntime local-NVMe contract
该测试只接受一个 --nvme,通过 public StorageRuntime API 验证 open、内存、
SINGLE/DUAL/LIST、batch、并发、超时和 capacity 行为。
build/cuda/bin/tutti_storage_runtime_local_nvme_contract_test \
--gpu 0 \
--nvme "$NVME1"
每个 runtime 申请 16 个 QP;assembly/open 会同时创建第二个 dp2 验证
mismatched key。因此同一 controller 需要 max_q_per_grp >= 16 且至少有
32 个 user QP。
请求 payload 固定为 4 KiB;block_size 只负责 LBA 换算。
2.3 Striped local-NVMe contract
该测试验证 striped resolver/DataPath 的跨盘读写、分片、重启持久性和 mixed batch:
build/cuda/bin/tutti_striped_local_nvme_contract_test \
--devices 2 \
--gpu 0 \
--nvme "$NVME0" \
--nvme "$NVME1"
--devices 只接受 2 或 4;缺少设备、mount 或 CUDA runtime 时返回 skip(77)。
所有选中的 namespace 必须有相同 block_size,且 allowed_gpus 包含 --gpu 0;
每个 selected controller 也要有至少 16 个 user QP。
3. 阶段 3 daemon allocation 补充
阶段 3 的 daemon canonical 配置使用 accelerators[].accel_id/view_root、
nvmes[].device_id/pci_addr/backing_mount_path/allowed_accel_ids。本节新增
接口与上面的历史 contract-test 参数同时存在;legacy-only 配置和 --gpu/--cuda
入口仍作为兼容路径保留,但 canonical 配置不得与 legacy 字段混用。
硬件测试或 client 应先通过 ListNvmeResources 读取本次 owner bring-up 返回的
device_id、pci_bdf、实际 chrdev_path/minor、block_path、namespace、page/
logical-block、BAR0 和 queue metadata,再生成 --nvme 参数。不得按 YAML 数组顺序、
accelerator ordinal 或设备 ID 拼接 /dev 路径;allocation 返回的 view_path 才是
accelerator 可见路径。
阶段 3 hardware gate 还覆盖 accelerator 0/1 的 allowed/explicit acquisition、一个
有序 striped allocation、共享 controller queue reservation、预算耗尽、统一 Release、
heartbeat/PID reaper 回收,以及 daemon list/acquire 前后无 accelerator compute context。
--skip-io 仅用于 attach 诊断,不能作为 validated_available 证据;最终验证必须对
每个 slice 执行 scratch 区域 write/read/verify 后再 Release 同一个 allocation。