hardware queue pair是什麼
hardware queue pair是我們理解nvme/spdk的牛鼻子,只有深入理解纔可能把nvme用好。
從nvme控制器寄存器的角度看
顧名思義,就是一些硬件寄存器組成的隊列。
空隊列
滿隊列
- 問題:
能否併發入隊、出隊?不行
submission hardware queue entry
每個entry如下表所示:
- 入隊:
host software 提交命令到tail entry, 通過操作submission hardware queue tail doorbell register;
- 出隊:
hardware 依次取head entry 去處理
completion hardware hardware queue entry
每個entry的主要fileds 如下:
-
入隊
hardware 處理完上面取到的nvme command之後,把對應的完成的信息放在completion queue head entry; - 出隊
host software 被中斷或主動輪詢到上面有新的entry 添加之後,去completion queue tail 去取最近提交的命令的處理結果。
這個主要是操作completion queue doorbell 寄存器去實現:
queue pair
nvme控制器內部有多個submission hardware queue,也有多個completion hardware queue。 提交、執行 NVME command的時候,需要使用上面兩種hardware queue中的entry,成對使用。
從nvme控制器架構的角度看
hardware queue pair 是抽取"nvme command"的水車。設計到NVME 指令的提交/執行和完成。
概覽
下面是一張經典的圖:
NVME command提交
NVME已完成命令的處理
spdk對hardware queue pair的封裝
IO請求提交函數
- spdk_nvme_ns_cmd_read
-
生產request
_nvme_ns_cmd_rw(ns, qpair, &payload, ....) -
提交請求
nvme_qpair_submmit_request()2.1 nvme_transport_qpair_submit_request(qpair, request)
2.1.1 nvme_pcie_qpair_submit_request (qpair, request)
2.1.1.1 nvme_pcie_qpair_build_contig_request(qpair, req, tr);
2.1.1.2 nvme_pcie_qpair_submit_tracker(qpair, tr)
nvme_pcie_qpair_submit_tracker(struct spdk_nvme_qpair *qpair, struct nvme_tracker *tr)
{
struct nvme_request *req;
struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair);
struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(qpair->ctrlr);
req = tr->req;
assert(req != NULL);
req->timed_out = false;
if (spdk_unlikely(pctrlr->ctrlr.timeout_enabled)) {
req->submit_tick = spdk_get_ticks();
} else {
req->submit_tick = 0;
}
pqpair->tr[tr->cid].active = true;
/* Copy the command from the tracker to the submission queue. */
nvme_pcie_copy_command(&pqpair->cmd[pqpair->sq_tail], &req->cmd);
if (spdk_unlikely(++pqpair->sq_tail == pqpair->num_entries)) {
pqpair->sq_tail = 0;
}
if (spdk_unlikely(pqpair->sq_tail == pqpair->sq_head)) {
SPDK_ERRLOG("sq_tail is passing sq_head!\n");
}
spdk_wmb();
if (spdk_likely(nvme_pcie_qpair_update_mmio_required(qpair,
pqpair->sq_tail,
pqpair->sq_shadow_tdbl,
pqpair->sq_eventidx))) {
g_thread_mmio_ctrlr = pctrlr;
spdk_mmio_write_4(pqpair->sq_tdbl, pqpair->sq_tail); // <---
g_thread_mmio_ctrlr = NULL;
}
}
通過上面code path可以看到,spdk nvme 需要操作硬件寄存器,並且一路無鎖和原子操作。需要上層保護。
IO完成查詢函數
spdk_nvme_qpair_process_completions
同上類似操作對應的cq_hdbel,無鎖和原子操作,需要上層保護,防止併發修改doorbell 寄存器。
如何用好多個hardware queue pair
需要管理好實際應用中hardware queue pair和線程、處理器核的對應關係,避免多個線程同時訪問某個hardware queue。