掌握SPDK 常用的API是深入理解SPDK的好方法。下面总结了SPDK 最主要的一些API。

public Interface

spdk/nvme.h
Key Functions   Description
spdk_nvme_probe()   Enumerate the bus indicated by the transport ID and attach the userspace NVMe driver to each device found if desired.
spdk_nvme_ctrlr_alloc_io_qpair()    Allocate an I/O queue pair (submission and completion queue).
spdk_nvme_ctrlr_get_ns()    Get a handle to a namespace for the given controller.
spdk_nvme_ns_cmd_read()     Submits a read I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_readv()    Submit a read I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_read_with_md()     Submits a read I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_write()    Submit a write I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_writev()   Submit a write I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_write_with_md()    Submit a write I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_write_zeroes()     Submit a write zeroes I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_dataset_management()   Submit a data set management request to the specified NVMe namespace.
spdk_nvme_ns_cmd_flush()    Submit a flush request to the specified NVMe namespace.
spdk_nvme_qpair_process_completions()   Process any outstanding completions for I/O submitted on a queue pair.
spdk_nvme_ctrlr_cmd_admin_raw()     Send the given admin command to the NVMe controller.
spdk_nvme_ctrlr_process_admin_completions()     Process any outstanding completions for admin commands.
spdk_nvme_ctrlr_cmd_io_raw()    Send the given NVM I/O command to the NVMe controller.
spdk_nvme_ctrlr_cmd_io_raw_with_md()    Send the given NVM I/O command with metadata to the NVMe controller. 

NVME Driver Design

NVME IO 提交

nvme_ns_cmd_xxx :以 nvme submittin queue entry 的形式 提交IO请求到queue pair; 无阻塞,提交完先于IO完成返回;

spdk_nvme_qpair_process_completions():应用程序通过这个API 在每个queue pair 上polling查询在飞 的IO是否完成;

扩展的性能

NVME 驱动内部的内存使用

  • 数据路径上zero-copy, 这事因为IO commands没有data buffer; 但是admin queue 可能含有数据copy,取决于用户使用的API;

  • 每一个queue队列 拥有一组跟踪调用者提交的命令的tracker;
  • tracker的数量 取决于用户输入(指定的) queue size 和从capacitity 寄存器Maximum Queue Entries Supported(MQES, 0 based value) 字段读回的值;
  • 每个tracker 4096 Bytes (4KB), 最大的maximum memory used for each I/O queue is: (MQES + 1) * 4 KiB.

  • spdk_nvme_qpair_process_completions().
  • SQE 64B (submit queue entry size)
  • CQE 16B (completion queue size)
  • 每个IO queue pair 最多需要的内存大小: (MQES + 1) * (64 + 16) Bytes
  • 上面的内存可以可以分配到host memory; 一些可能把它放到PCI memory bar上

    SPDK 内部代码层次

    代码是被分层的:

  • 底层: nvme 命令层; API包括spdk_nvme_xxxx: 所在文件在:
    示例程序:examples/nvme/hello_world/hello_world.c
  • 中间层: spdk bdev 层,疯转了好需要更多细节的nvme command ,提供对外的类似操作块一样的接口:spdk_blk_xxxx;
    示例程序:.//examples/bdev/hello_world/hello_bdev.c
  • 上层:blob 实现了上面类似于快的块资源分配的功能;
    示例程序:.//examples/blob/hello_world/hello_blob.c

  • 应用层: blobfs 实现了非POSIX的资源管理和申请、分配;
    ( demo用那种形式写块?可读性高?)

问题:上面基于nvme. 命令和bdev接口的对nvme SSD的读写的对比,性能方便回有什么损失么?为什么?