SPDK 自带的性能测试应用 spdk_nvme_perf
的源代码 perf.c
的粗浅分析,进一步熟悉 SPDK 用户态驱动的主要工作流程和方式。
简介
perf 是 SPDK 用来测试 NVMe SSD 性能的工具,最新版本的 SPDK 中 perf 源代码在 spdk/app/spdk_nvme_perf/
路径下。perf 主要用来测试 NVMe SSD 的 IOPS,Bandwidth 和 Latency,它既可以测本地的 target,也可以测远端的 target。
perf 主流程
perf 资源
TODO
函数调用栈 + 控制流程图 + 数据流程图,按照不同流程图分章节跟进重要函数中去;
所有用到的重要资源,如
spdk_nvme_ctrlr
、spdk_nvme_ns
数据结构等,理清他们的关系,类似于 UML 类图;controller 状态转移图。
函数调用栈说明:
相同缩进表示同一层的函数执行;不同缩进表示存在函数内调用另一个函数。
花括号表示循环体。
函数结尾
;
表示该函数结束;:
表示进入该函数,接下来存在函数调用。
(一)控制流(初始化)
流程图:
函数调用栈:
spdk_env_opts_init(&opts);
parse_args(...):
while {
getopt_long(..., g_perf_cmdline_opts, ...);
add_trid(...);
...
}
spdk_env_init(&opts);
register_workers():
SPDK_ENV_FOREACH_CORE(i) {
worker = calloc(...);
}
TAILQ_INIT(&worker->ns_ctx);
TAILQ_INSERT_TAIL(&g_workers, worker, link);
register_controllers():
TAILQ_FOREACH(trid_entry, &g_trid_list, tailq) {
spdk_nvme_probe(&trid_entry->trid, trid_entry, probe_cb, attach_cb, NULL):
probe_ctx = spdk_nvme_probe_async(...):
nvme_driver_init();
probe_ctx = calloc(...);
nvme_probe_ctx_init(probe_ctx, ...):
TAILQ_INIT(&probe_ctx->init_ctrlrs);
nvme_probe_internal(probe_ctx, false):
nvme_rdma.c: nvme_fabric_ctrlr_scan(probe_ctx, ...):
(该函数调用见后文、这里面的函数调用创建 nvme_ctrlr、获取了 subnqn 等)
nvme_init_controllers(probe_ctx):
spdk_nvme_probe_poll_async(probe_ctx):
TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, ...) {
nvme_ctrlr_poll_internal(ctrlr, probe_ctx):
nvme_ctrlr_process_init(ctrlr):
(该函数调用见后文、这里面的函数调用获取了 ns)
TAILQ_REMOVE(&probe_ctx->init_ctrlrs, ctrlr, ...);
TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs, ctrlr, tailq);
perf.c: attach_cb(...):
register_ctrlr(ctrlr, trid_entry):
TAILQ_INSERT_TAIL(&g_controllers, ctrlr_entry, ...);
(该函数剩余的函数调用见后文)
}
}
(二)控制流(初始化 - fabric_ctrlr_scan)
初始化过程中 Controller 状态转移图:
流程图:
函数调用栈:
nvme_rdma.c: nvme_fabric_ctrlr_scan(probe_ctx, ...):
(三)控制流(初始化 - ctrlr_process_init)
流程图:
函数调用栈:
nvme_ctrlr_process_init(ctrlr):
_nvme_ctrlr_identify_active_ns(ctrlr):
ctx = nvme_active_ns_ctx_create(ctrlr, _nvme_active_ns_ctx_deleter); (绑定 deleter)
nvme_ctrlr_identify_active_ns_async(ctx):
nvme_ctrlr_cmd_identify(ctrlr, ..., nvme_ctrlr_identify_active_ns_async_done, ctx); (_done 函数为回调)
nvme_ctrlr_identify_active_ns_async_done():
_nvme_active_ns_ctx_deleter(): (函数指针)
nvme_ctrlr_identify_active_ns_swap(ctrlr, ctx->new_ns_list, ...):
nvme_ctrlr_construct_namespace(ctrlr, nsid):
spdk_nvme_ctrlr_get_ns(ctrlr, nsid):
RB_INSERT(nvme_ns_tree, &ctrlr->ns, ns);
()控制流(初始化 - register_ns)
流程图:
()控制流(任务执行)
流程图:
()数据流(发送)
流程图:
()数据流(接收)
流程图: