diff --git a/README.md b/README.md index 36eed8c..48563eb 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ zvfs的测试结果: 1. 大块4K:1460MiB/s 2. 小块128K:1266MiB/s +非对齐情况下,写入性能/2,因为需要read-update-write。 + ### spdk_nvme_perf 性能基准测试 ```shell cd /home/lian/share/10.1-spdk/spdk @@ -164,6 +166,55 @@ READ: === all tests PASSED === ``` +#### no O_DIRECT 随机 对齐 大块 +```shell +root@ubuntu:/home/lian/share/10.1-spdk/zvfs/zvfs# ./func_test + +=== test_single_file_random_perf === +Path : /tmp/test.dat +IO size : 128 KB +Range : 2048 MB +Duration: 10 sec + +RANDOM WRITE: + total : 8930.8 MB + time : 10.001 sec + IOPS : 7144 ops/sec + BW : 893.01 MB/s + +RANDOM READ: + total : 8238.9 MB + time : 10.000 sec + IOPS : 6591 ops/sec + BW : 823.89 MB/s + +=== all tests PASSED === +``` +#### no O_DIRECT 随机 非对齐 大块 +```shell +root@ubuntu:/home/lian/share/10.1-spdk/zvfs/zvfs# ./func_test + +=== test_single_file_random_perf === +Path : /tmp/test.dat +IO size : 128 KB +Range : 2048 MB +Duration: 10 sec + +RANDOM WRITE: + total : 5964.4 MB + time : 10.000 sec + IOPS : 4771 ops/sec + BW : 596.43 MB/s + +RANDOM READ: + total : 6607.8 MB + time : 10.000 sec + IOPS : 5286 ops/sec + BW : 660.77 MB/s + +=== all tests PASSED === +``` + #### O_DIRECT 小块 ```shell root@ubuntu:/home/lian/share/10.1-spdk/zvfs# ./func_test @@ -288,6 +339,55 @@ READ: === all tests PASSED === ``` +#### 对齐随机写(大块) +```shell +root@ubuntu:/home/lian/share/10.1-spdk/zvfs/zvfs# LD_PRELOAD=./libzvfs.so ./func_test /zvfs + +=== test_single_file_random_perf === +Path : /zvfs/file.dat +IO size : 128 KB +Range : 2048 MB +Duration: 10 sec + +RANDOM WRITE: + total : 17461.8 MB + time : 10.000 sec + IOPS : 13969 ops/sec + BW : 1746.17 MB/s + +RANDOM READ: + total : 17439.5 MB + time : 10.000 sec + IOPS : 13952 ops/sec + BW : 1743.95 MB/s + +=== all tests PASSED === +``` +#### 非对齐随机写(大块) +```shell +root@ubuntu:/home/lian/share/10.1-spdk/zvfs/zvfs# LD_PRELOAD=./libzvfs.so ./func_test /zvfs + +=== test_single_file_random_perf === +Path : /zvfs/file.dat +IO size : 128 KB +Range : 2048 MB +Duration: 10 sec + +RANDOM WRITE: + total : 7500.2 MB + time : 10.000 sec + IOPS : 6000 ops/sec + BW : 750.02 MB/s + +RANDOM READ: + total : 15143.8 MB + time : 10.000 sec + IOPS : 12115 ops/sec + BW : 1514.35 MB/s + +=== all tests PASSED === +``` + ## SPDK 1. blob_store: blob仓库,管理多个blob对象。 2. blob: 存储对象,逻辑上连续,物理上不一定连续。相当于文件。 diff --git a/zvfs/func_test.c b/zvfs/func_test.c index fd27b30..102b3da 100644 --- a/zvfs/func_test.c +++ b/zvfs/func_test.c @@ -102,6 +102,238 @@ static int test_single_file_perf(const char *path) return 0; } +static int test_single_file_random_perf(const char *path) +{ + size_t io_size = 128 * 1024; + size_t max_size = 2ULL * 1024 * 1024 * 1024; + size_t max_count = max_size / io_size; + int test_sec = 10; + int direct = 0; + + printf("\n=== test_single_file_random_perf ===\n"); + printf("Path : %s\n", path); + printf("IO size : %zu KB\n", io_size / 1024); + printf("Range : %zu MB\n", max_size / 1024 / 1024); + printf("Duration: %d sec\n", test_sec); + + srand(0x1234); + + char *buf = aligned_alloc(4096, io_size); + if (!buf) { perror("aligned_alloc"); return 1; } + memset(buf, 'A', io_size); + + struct timespec t1, t2, now; + + unlink(path); + + /* ================= RANDOM WRITE ================= */ + int fd = open(path, O_CREAT | O_RDWR | direct, 0644); + if (fd < 0) { perror("open rand write"); free(buf); return 2; } + + clock_gettime(CLOCK_MONOTONIC, &t1); + + size_t wcount = 0; + + do { + size_t blk = rand() % max_count; + off_t offset = (off_t)blk * io_size; + + if (lseek(fd, offset, SEEK_SET) < 0) { + perror("lseek rand write"); + close(fd); + free(buf); + return 3; + } + + if (write(fd, buf, io_size) != (ssize_t)io_size) { + perror("rand write"); + close(fd); + free(buf); + return 4; + } + + wcount++; + clock_gettime(CLOCK_MONOTONIC, &now); + + } while (time_diff_sec(t1, now) < test_sec); + + clock_gettime(CLOCK_MONOTONIC, &t2); + close(fd); + + double wsec = time_diff_sec(t1, t2); + double wmb = (double)wcount * io_size / 1024 / 1024; + + printf("\nRANDOM WRITE:\n"); + printf(" total : %.1f MB\n", wmb); + printf(" time : %.3f sec\n", wsec); + printf(" IOPS : %.0f ops/sec\n", wcount / wsec); + printf(" BW : %.2f MB/s\n", wmb / wsec); + + + /* ================= RANDOM READ ================= */ + fd = open(path, O_RDONLY | direct); + if (fd < 0) { perror("open rand read"); free(buf); return 5; } + + clock_gettime(CLOCK_MONOTONIC, &t1); + + size_t rcount = 0; + + do { + size_t blk = rand() % max_count; + off_t offset = (off_t)blk * io_size; + + if (lseek(fd, offset, SEEK_SET) < 0) { + perror("lseek rand read"); + close(fd); + free(buf); + return 6; + } + + ssize_t r = read(fd, buf, io_size); + if (r < 0) { + perror("rand read"); + close(fd); + free(buf); + return 7; + } + + rcount++; + clock_gettime(CLOCK_MONOTONIC, &now); + + } while (time_diff_sec(t1, now) < test_sec); + + clock_gettime(CLOCK_MONOTONIC, &t2); + close(fd); + + double rsec = time_diff_sec(t1, t2); + double rmb = (double)rcount * io_size / 1024 / 1024; + + printf("\nRANDOM READ:\n"); + printf(" total : %.1f MB\n", rmb); + printf(" time : %.3f sec\n", rsec); + printf(" IOPS : %.0f ops/sec\n", rcount / rsec); + printf(" BW : %.2f MB/s\n", rmb / rsec); + + unlink(path); + free(buf); + return 0; +} + +static int test_single_file_random_noaligned_perf(const char *path) +{ + size_t io_size = 128 * 1024; + size_t max_size = 2ULL * 1024 * 1024 * 1024; + size_t max_count = max_size / io_size; + int test_sec = 10; + int direct = 0; + + printf("\n=== test_single_file_random_perf ===\n"); + printf("Path : %s\n", path); + printf("IO size : %zu KB\n", io_size / 1024); + printf("Range : %zu MB\n", max_size / 1024 / 1024); + printf("Duration: %d sec\n", test_sec); + + srand(0x1234); + + char *buf = aligned_alloc(4096, io_size); + if (!buf) { perror("aligned_alloc"); return 1; } + memset(buf, 'A', io_size); + + struct timespec t1, t2, now; + + unlink(path); + + /* ================= RANDOM WRITE ================= */ + int fd = open(path, O_CREAT | O_RDWR | direct, 0644); + if (fd < 0) { perror("open rand write"); free(buf); return 2; } + + clock_gettime(CLOCK_MONOTONIC, &t1); + + size_t wcount = 0; + + do { + off_t offset = (off_t)(rand() % (max_size - io_size)); + + if (lseek(fd, offset, SEEK_SET) < 0) { + perror("lseek rand write"); + close(fd); + free(buf); + return 3; + } + + if (write(fd, buf, io_size) != (ssize_t)io_size) { + perror("rand write"); + close(fd); + free(buf); + return 4; + } + + wcount++; + clock_gettime(CLOCK_MONOTONIC, &now); + + } while (time_diff_sec(t1, now) < test_sec); + + clock_gettime(CLOCK_MONOTONIC, &t2); + close(fd); + + double wsec = time_diff_sec(t1, t2); + double wmb = (double)wcount * io_size / 1024 / 1024; + + printf("\nRANDOM WRITE:\n"); + printf(" total : %.1f MB\n", wmb); + printf(" time : %.3f sec\n", wsec); + printf(" IOPS : %.0f ops/sec\n", wcount / wsec); + printf(" BW : %.2f MB/s\n", wmb / wsec); + + + /* ================= RANDOM READ ================= */ + fd = open(path, O_RDONLY | direct); + if (fd < 0) { perror("open rand read"); free(buf); return 5; } + + clock_gettime(CLOCK_MONOTONIC, &t1); + + size_t rcount = 0; + + do { + off_t offset = (off_t)(rand() % (max_size - io_size)); + + if (lseek(fd, offset, SEEK_SET) < 0) { + perror("lseek rand read"); + close(fd); + free(buf); + return 6; + } + + ssize_t r = read(fd, buf, io_size); + if (r < 0) { + perror("rand read"); + close(fd); + free(buf); + return 7; + } + + rcount++; + clock_gettime(CLOCK_MONOTONIC, &now); + + } while (time_diff_sec(t1, now) < test_sec); + + clock_gettime(CLOCK_MONOTONIC, &t2); + close(fd); + + double rsec = time_diff_sec(t1, t2); + double rmb = (double)rcount * io_size / 1024 / 1024; + + printf("\nRANDOM READ:\n"); + printf(" total : %.1f MB\n", rmb); + printf(" time : %.3f sec\n", rsec); + printf(" IOPS : %.0f ops/sec\n", rcount / rsec); + printf(" BW : %.2f MB/s\n", rmb / rsec); + + unlink(path); + free(buf); + return 0; +} + /* ------------------------------------------------------------------ */ /* Test 1: 原有基础测试 */ /* ------------------------------------------------------------------ */ @@ -402,7 +634,9 @@ int main(int argc, char **argv) // rc |= test_lseek(path); // rc |= test_dual_open_same_file(path); // rc |= test_two_files(path_a, path_b); - rc |= test_single_file_perf(path); + // rc |= test_single_file_perf(path); + // rc |= test_single_file_random_perf(path); + rc |= test_single_file_random_noaligned_perf(path); printf("\n=== all tests %s ===\n", rc == 0 ? "PASSED" : "FAILED");