zvfs: 性能测试
This commit is contained in:
134
zvfs.c
134
zvfs.c
@@ -4,6 +4,10 @@
|
||||
#undef SPDK_DEBUGLOG
|
||||
#define SPDK_DEBUGLOG(...) do {} while(0)
|
||||
|
||||
#define ZVFS_BDEV "Nvme0n1"
|
||||
#ifndef ZVFS_BDEV
|
||||
#define ZVFS_BDEV "Malloc0"
|
||||
#endif
|
||||
|
||||
struct spdk_thread *global_thread = NULL;
|
||||
const char *json_file = "/home/lian/share/10.1-spdk/zvfs/zvfs.json";
|
||||
@@ -114,18 +118,29 @@ bool waiter(struct spdk_thread *thread, spdk_msg_fn start_fn, void *ctx, bool *f
|
||||
/* MOUNT */
|
||||
/* ================================================================== */
|
||||
void zvfs_do_mount(void *arg) {
|
||||
|
||||
zvfs_t *fs = (zvfs_t*)arg;
|
||||
|
||||
struct spdk_bs_dev *bs_dev = NULL;
|
||||
|
||||
int rc = spdk_bdev_create_bs_dev_ext("Malloc0", zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
|
||||
// SPDK_DEBUGLOG("=== Listing ALL bdevs after JSON load ===\n");
|
||||
// struct spdk_bdev *bdev = spdk_bdev_first();
|
||||
// while (bdev) {
|
||||
// SPDK_DEBUGLOG("Found bdev: [%s] product: %s\n",
|
||||
// spdk_bdev_get_name(bdev),
|
||||
// spdk_bdev_get_product_name(bdev));
|
||||
// bdev = spdk_bdev_next(bdev);
|
||||
// }
|
||||
// SPDK_DEBUGLOG("---------------------------------\n");
|
||||
// SPDK_DEBUGLOG("Trying to open: %s\n", ZVFS_BDEV);
|
||||
|
||||
int rc = spdk_bdev_create_bs_dev_ext(ZVFS_BDEV, zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
|
||||
if (rc != 0) {
|
||||
spdk_app_stop(0);
|
||||
SPDK_ERRLOG("=== bdev_open FAILED rc=%d (probably still not registered) ===\n", rc);
|
||||
fs->finished = true;
|
||||
spdk_app_stop(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
fs->bs_dev = bs_dev;
|
||||
// spdk_bs_init(bs_dev, NULL, zvfs_spdk_bs_init_cb, fs);
|
||||
spdk_bs_load(bs_dev, NULL, zvfs_spdk_bs_load_cb, fs);
|
||||
}
|
||||
|
||||
@@ -136,7 +151,7 @@ void zvfs_spdk_bs_load_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
|
||||
SPDK_DEBUGLOG("load failed, new device, re-create bs_dev and init\n");
|
||||
|
||||
struct spdk_bs_dev *bs_dev = NULL;
|
||||
int rc = spdk_bdev_create_bs_dev_ext("Malloc0", zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
|
||||
int rc = spdk_bdev_create_bs_dev_ext(ZVFS_BDEV, zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("re-create bs_dev failed\n");
|
||||
spdk_app_stop(-1);
|
||||
@@ -150,7 +165,8 @@ void zvfs_spdk_bs_load_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
|
||||
|
||||
uint64_t io_unit_size = spdk_bs_get_io_unit_size(bs);
|
||||
SPDK_DEBUGLOG("io_unit_size : %"PRIu64"\n", io_unit_size);
|
||||
|
||||
SPDK_NOTICELOG("io_unit_size=%lu\n", io_unit_size);
|
||||
|
||||
fs->io_unit_size = io_unit_size;
|
||||
fs->bs = bs;
|
||||
fs->channel = spdk_bs_alloc_io_channel(fs->bs);
|
||||
@@ -167,6 +183,7 @@ void zvfs_spdk_bs_init_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
|
||||
|
||||
uint64_t io_unit_size = spdk_bs_get_io_unit_size(bs);
|
||||
SPDK_DEBUGLOG("io_unit_size : %"PRIu64"\n", io_unit_size);
|
||||
SPDK_NOTICELOG("io_unit_size=%lu\n", io_unit_size);
|
||||
|
||||
fs->io_unit_size = io_unit_size;
|
||||
fs->bs = bs;
|
||||
@@ -370,17 +387,38 @@ void zvfs_do_write(void *arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 先把涉及的扇区读出,read 完成后在 preread_cb 里 patch 数据再写。
|
||||
* 注意:把用户数据暂存在 file->write_buf / write_count,
|
||||
* 或者借用 file->io_count(io_count 不变)。
|
||||
* 这里我们把用户数据已经由上层调用者拷贝到了 write_staging_buf,
|
||||
*/
|
||||
/* 不管是否需要扩容,先 preread */
|
||||
spdk_blob_io_read(file->blob, file->fs->channel,
|
||||
file->dma_buf,
|
||||
lba, lba_count,
|
||||
zvfs_spdk_blob_write_preread_cb, file);
|
||||
file->aligned = (file->current_offset % io_unit == 0) &&
|
||||
(file->io_count % io_unit == 0);
|
||||
|
||||
// static uint64_t aligned_count = 0;
|
||||
// static uint64_t unaligned_count = 0;
|
||||
// if (aligned) {
|
||||
// aligned_count++;
|
||||
// } else {
|
||||
// unaligned_count++;
|
||||
// }
|
||||
// if ((aligned_count + unaligned_count) % 1000 == 0) {
|
||||
// printf("aligned=%lu unaligned=%lu\n", aligned_count, unaligned_count);
|
||||
// }
|
||||
|
||||
if (file->aligned) {
|
||||
/* 直接把用户数据拷到 dma_buf,跳过 preread */
|
||||
memcpy(file->dma_buf, file->write_staging_buf, file->io_count);
|
||||
/* 直接进 preread_cb 的后半段逻辑(扩容判断+写) */
|
||||
zvfs_spdk_blob_write_preread_cb(file, 0);
|
||||
} else {
|
||||
/*
|
||||
* 先把涉及的扇区读出,read 完成后在 preread_cb 里 patch 数据再写。
|
||||
* 注意:把用户数据暂存在 file->write_buf / write_count,
|
||||
* 或者借用 file->io_count(io_count 不变)。
|
||||
* 这里我们把用户数据已经由上层调用者拷贝到了 write_staging_buf,
|
||||
*/
|
||||
/* 不管是否需要扩容,先 preread */
|
||||
spdk_blob_io_read(file->blob, file->fs->channel,
|
||||
file->dma_buf,
|
||||
lba, lba_count,
|
||||
zvfs_spdk_blob_write_preread_cb, file);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 2 : preread 完成,patch dma_buf,然后决定是否扩容 */
|
||||
@@ -393,11 +431,15 @@ void zvfs_spdk_blob_write_preread_cb(void *arg, int bserrno){
|
||||
SPDK_DEBUGLOG("preread error %d (may be uninitialized, continue)\n", bserrno);
|
||||
}
|
||||
|
||||
/* patch:把用户数据覆写到 dma_buf 的正确偏移处 */
|
||||
uint64_t page_off = file->current_offset % file->fs->io_unit_size;
|
||||
memcpy((uint8_t *)file->dma_buf + page_off,
|
||||
file->write_staging_buf,
|
||||
file->io_count);
|
||||
/* 只有非对齐情况才需要 patch,对齐情况下数据已经在 dma_buf 里了(do_write 里拷好的)*/
|
||||
uint64_t io_unit = file->fs->io_unit_size;
|
||||
|
||||
if (!file->aligned) {
|
||||
uint64_t page_off = file->current_offset % io_unit;
|
||||
memcpy((uint8_t *)file->dma_buf + page_off,
|
||||
file->write_staging_buf,
|
||||
file->io_count);
|
||||
}
|
||||
|
||||
/* 判断是否需要扩容 */
|
||||
uint64_t end_byte = file->current_offset + file->io_count;
|
||||
@@ -547,7 +589,6 @@ void zvfs_spdk_bs_unload_cb(void *arg, int bserrno) {
|
||||
|
||||
// setup
|
||||
// zvfs.json
|
||||
|
||||
int zvfs_env_setup(void) {
|
||||
struct spdk_env_opts opts;
|
||||
spdk_env_opts_init(&opts);
|
||||
@@ -572,10 +613,26 @@ int zvfs_env_setup(void) {
|
||||
spdk_set_thread(global_thread);
|
||||
|
||||
bool done = false;
|
||||
|
||||
waiter(global_thread, zvfs_json_load_fn, &done, &done);
|
||||
SPDK_DEBUGLOG("zvfs_env_setup complete\n");
|
||||
|
||||
int retry = 0;
|
||||
while (retry < 200) { // 最多等 20 秒
|
||||
spdk_thread_poll(global_thread, 0, 0);
|
||||
if (spdk_bdev_get_by_name(ZVFS_BDEV) != NULL) {
|
||||
SPDK_DEBUGLOG("bdev %s ready!\n", ZVFS_BDEV);
|
||||
break;
|
||||
}
|
||||
usleep(100 * 1000); // 100ms
|
||||
retry++;
|
||||
}
|
||||
|
||||
if (spdk_bdev_get_by_name(ZVFS_BDEV) == NULL) {
|
||||
SPDK_ERRLOG("bdev %s not found after 20s timeout!\n", ZVFS_BDEV);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
SPDK_DEBUGLOG("zvfs_env_setup complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -586,9 +643,12 @@ void zvfs_json_load_fn(void *arg) {
|
||||
}
|
||||
|
||||
void json_app_load_done(int rc, void *ctx) {
|
||||
bool *done = ctx;
|
||||
*done = true;
|
||||
SPDK_DEBUGLOG("json_app_load_done\n");
|
||||
bool *done = ctx;
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("JSON config load FAILED! rc=%d\n", rc);
|
||||
}
|
||||
// 不要 sleep!直接标记完成,让外部 waiter 去轮询
|
||||
*done = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -600,14 +660,14 @@ void json_app_load_done(int rc, void *ctx) {
|
||||
int zvfs_mount(struct zvfs_s *fs) {
|
||||
fs->finished = false;
|
||||
bool ok = waiter(global_thread, zvfs_do_mount, fs, &fs->finished);
|
||||
SPDK_DEBUGLOG("mount finished\n");
|
||||
if(!ok) SPDK_ERRLOG("mount result: ok=%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
// unload
|
||||
int zvfs_umount(struct zvfs_s *fs) {
|
||||
fs->finished = false;
|
||||
bool ok = waiter(global_thread, zvfs_do_umount, fs, &fs->finished);
|
||||
SPDK_DEBUGLOG("umount finished\n");
|
||||
if(!ok) SPDK_ERRLOG("umount result: ok=%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
// file
|
||||
@@ -615,14 +675,14 @@ int zvfs_umount(struct zvfs_s *fs) {
|
||||
int zvfs_create(struct zvfs_file_s *file) {
|
||||
file->finished = false;
|
||||
bool ok = waiter(global_thread, zvfs_do_create, file, &file->finished);
|
||||
SPDK_DEBUGLOG("create finished\n");
|
||||
if(!ok) SPDK_ERRLOG("create result: ok=%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
// open
|
||||
int zvfs_open(struct zvfs_file_s *file) {
|
||||
file->finished = false;
|
||||
bool ok = waiter(global_thread, zvfs_do_open, file, &file->finished);
|
||||
SPDK_DEBUGLOG("open finished\n");
|
||||
if(!ok) SPDK_ERRLOG("open result: ok=%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
// read
|
||||
@@ -632,6 +692,7 @@ int zvfs_read(struct zvfs_file_s *file, uint8_t *buffer, size_t count) {
|
||||
file->finished = false;
|
||||
|
||||
bool ok = waiter(global_thread, zvfs_do_read, file, &file->finished);
|
||||
if(!ok) SPDK_ERRLOG("read result: ok=%d\n", ok);
|
||||
if (!ok || file->actual_io_count == 0) return -1;
|
||||
|
||||
/*
|
||||
@@ -649,7 +710,6 @@ int zvfs_read(struct zvfs_file_s *file, uint8_t *buffer, size_t count) {
|
||||
(uint8_t *)file->dma_buf + page_off,
|
||||
file->actual_io_count);
|
||||
|
||||
SPDK_DEBUGLOG("read finished\n");
|
||||
return (int)file->actual_io_count;
|
||||
}
|
||||
// write
|
||||
@@ -659,21 +719,21 @@ int zvfs_write(struct zvfs_file_s *file, const uint8_t *buffer, size_t count) {
|
||||
file->finished = false;
|
||||
|
||||
bool ok = waiter(global_thread, zvfs_do_write, file, &file->finished);
|
||||
SPDK_DEBUGLOG("write finished\n");
|
||||
if(!ok) SPDK_ERRLOG("write result: ok=%d\n", ok);
|
||||
return ok ? (int)count : -1;
|
||||
}
|
||||
// close
|
||||
int zvfs_close(struct zvfs_file_s *file) {
|
||||
file->finished = false;
|
||||
bool ok = waiter(global_thread, zvfs_do_close, file, &file->finished);
|
||||
SPDK_DEBUGLOG("close finished\n");
|
||||
if(!ok) SPDK_ERRLOG("close result: ok=%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
// delete
|
||||
int zvfs_delete(struct zvfs_file_s *file) {
|
||||
file->finished = false;
|
||||
bool ok = waiter(global_thread, zvfs_do_delete, file, &file->finished);
|
||||
SPDK_DEBUGLOG("delete finished\n");
|
||||
if(!ok) SPDK_ERRLOG("delete result: ok=%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user