Files
zvfs/func_test.c
2026-02-24 16:01:29 +00:00

410 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
static double time_diff_sec(struct timespec a, struct timespec b)
{
return (b.tv_sec - a.tv_sec) +
(b.tv_nsec - a.tv_nsec) / 1000000000.0;
}
static int test_single_file_perf(const char *path)
{
// size_t io_size = 128 * 1024;
size_t io_size = 4096;
size_t max_size = 2ULL * 1024 * 1024 * 1024; /* 最大 2GB循环覆写 */
size_t max_count = max_size / io_size;
int test_sec = 10;
int direct = 0;
printf("\n=== test_single_file_perf ===\n");
printf("Path : %s\n", path);
printf("IO size : %zu KB\n", io_size / 1024);
printf("Max file: %zu MB\n", max_size / 1024 / 1024);
printf("Duration: %d sec\n", test_sec);
unlink(path);
char *buf = aligned_alloc(4096, io_size);
if (!buf) { perror("aligned_alloc"); return 1; }
memset(buf, 'A', io_size);
struct timespec t1, t2, now;
/* ================= WRITE ================= */
int fd = open(path, O_CREAT | O_RDWR | direct, 0644);
if (fd < 0) { perror("open write"); free(buf); return 1; }
clock_gettime(CLOCK_MONOTONIC, &t1);
size_t wcount = 0;
size_t wpos = 0; /* 当前写位置(以块为单位) */
do {
/* 超过最大文件大小seek 回头循环覆写 */
if (wpos >= max_count) {
lseek(fd, 0, SEEK_SET);
wpos = 0;
}
if (write(fd, buf, io_size) != (ssize_t)io_size) {
perror("write");
close(fd);
free(buf);
return 2;
}
wcount++;
wpos++;
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.0 * 1024.0);
printf("\nWRITE:\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);
/* ================= READ ================= */
fd = open(path, O_RDONLY | direct);
if (fd < 0) { perror("open read"); free(buf); return 3; }
clock_gettime(CLOCK_MONOTONIC, &t1);
size_t rcount = 0;
do {
ssize_t r = read(fd, buf, io_size);
if (r <= 0) {
lseek(fd, 0, SEEK_SET);
continue;
}
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.0 * 1024.0);
printf("\nREAD:\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: 原有基础测试 */
/* ------------------------------------------------------------------ */
static int test_basic(const char *path)
{
printf("\n=== test_basic ===\n");
printf("open: %s\n", path);
int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd < 0) { perror("open"); return 1; }
const char *msg = "ABCDEFGHIJKL";
ssize_t w = write(fd, msg, strlen(msg));
if (w < 0) { perror("write"); return 2; }
printf("write: %zd\n", w);
const char *msg2 = "MNOPQRSTUVWXYZ";
ssize_t w2 = write(fd, msg2, strlen(msg2));
if (w2 < 0) { perror("write"); return 2; }
printf("write: %zd\n", w2);
close(fd);
fd = open(path, O_RDONLY);
if (fd < 0) { perror("open R"); return 3; }
char buf[10];
memset(buf, 0, sizeof(buf));
ssize_t r = read(fd, buf, sizeof(buf));
if (r < 0) { perror("read"); return 4; }
printf("read: %zd bytes: %.*s\n", r, (int)r, buf);
char buf2[512];
memset(buf2, 0, sizeof(buf2));
ssize_t r2 = read(fd, buf2, sizeof(buf2));
if (r2 < 0) { perror("read"); return 4; }
printf("read: %zd bytes: %.*s\n", r2, (int)r2, buf2);
close(fd);
if (unlink(path) != 0) { perror("unlink"); return 5; }
printf("unlink: ok\n");
return 0;
}
/* ------------------------------------------------------------------ */
/* Test 2: lseek */
/* ------------------------------------------------------------------ */
static int test_lseek(const char *path)
{
printf("\n=== test_lseek ===\n");
int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd < 0) { perror("open"); return 1; }
/* 写入 26 个字母 */
const char *alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (write(fd, alpha, 26) != 26) { perror("write"); return 2; }
printf("write 26 bytes: %s\n", alpha);
/* SEEK_SET: 跳到第 0 字节,读 5 个 */
off_t pos = lseek(fd, 0, SEEK_SET);
printf("lseek SEEK_SET 0 -> %ld\n", (long)pos);
char buf[32] = {0};
ssize_t r = read(fd, buf, 5);
printf("read 5 bytes: %.*s (expect: ABCDE)\n", (int)r, buf);
/* SEEK_CUR: 从当前位置5再向前跳 3 个,应读到第 8 字节 'I' */
pos = lseek(fd, 3, SEEK_CUR);
printf("lseek SEEK_CUR +3 -> %ld\n", (long)pos);
memset(buf, 0, sizeof(buf));
r = read(fd, buf, 5);
printf("read 5 bytes: %.*s (expect: IJKLM)\n", (int)r, buf);
/* SEEK_END: 从文件尾往回 5 字节,读到最后 5 个字母 */
pos = lseek(fd, -5, SEEK_END);
printf("lseek SEEK_END -5 -> %ld\n", (long)pos);
memset(buf, 0, sizeof(buf));
r = read(fd, buf, 10); /* 最多只剩 5 字节 */
printf("read %zd bytes: %.*s (expect: VWXYZ)\n", r, (int)r, buf);
/* SEEK_SET 超过文件末尾:写一个字节,制造"空洞" */
pos = lseek(fd, 30, SEEK_SET);
printf("lseek SEEK_SET 30 -> %ld\n", (long)pos);
if (write(fd, "!", 1) != 1) { perror("write hole"); return 3; }
/* 重新读回空洞区域,[26,29] 应为 0x00 */
lseek(fd, 26, SEEK_SET);
memset(buf, 0xAA, sizeof(buf));
r = read(fd, buf, 5);
printf("read hole+1: %zd bytes, hole[0]=%02X hole[1]=%02X hole[2]=%02X "
"hole[3]=%02X last='%c' (expect: 00 00 00 00 '!')\n",
r, (unsigned char)buf[0], (unsigned char)buf[1],
(unsigned char)buf[2], (unsigned char)buf[3], buf[4]);
close(fd);
unlink(path);
return 0;
}
/* ------------------------------------------------------------------ */
/* Test 3: 同一文件被两个 fd 同时打开(一读一写) */
/* ------------------------------------------------------------------ */
static int test_dual_open_same_file(const char *path)
{
printf("\n=== test_dual_open_same_file ===\n");
/* 先创建并写入初始内容 */
int fd_init = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd_init < 0) { perror("open init"); return 1; }
const char *init = "0123456789";
if (write(fd_init, init, 10) != 10) { perror("write init"); return 2; }
close(fd_init);
/* 用写句柄和读句柄分别打开同一文件 */
int fd_w = open(path, O_WRONLY);
if (fd_w < 0) { perror("open W"); return 3; }
int fd_r = open(path, O_RDONLY);
if (fd_r < 0) { perror("open R"); return 4; }
printf("fd_w=%d fd_r=%d\n", fd_w, fd_r);
/* 通过写句柄覆写前 5 字节 */
if (write(fd_w, "HELLO", 5) != 5) { perror("write"); return 5; }
printf("write via fd_w: HELLO (overwrite first 5 bytes)\n");
/* 通过读句柄从头读回全部内容 */
char buf[32] = {0};
lseek(fd_r, 0, SEEK_SET);
ssize_t r = read(fd_r, buf, sizeof(buf));
printf("read via fd_r: %zd bytes: %.*s (expect: HELLO56789)\n",
r, (int)r, buf);
/* 继续用写句柄追加 */
lseek(fd_w, 0, SEEK_END);
if (write(fd_w, "!!!", 3) != 3) { perror("write append"); return 6; }
printf("write append via fd_w: !!!\n");
/* 读句柄读追加部分 */
lseek(fd_r, 10, SEEK_SET);
memset(buf, 0, sizeof(buf));
r = read(fd_r, buf, sizeof(buf));
printf("read appended via fd_r: %zd bytes: %.*s (expect: !!!)\n",
r, (int)r, buf);
close(fd_w);
close(fd_r);
unlink(path);
return 0;
}
/* ------------------------------------------------------------------ */
/* Test 4: 两个不同文件同时打开,分别读写 */
/* ------------------------------------------------------------------ */
static int test_two_files(const char *path_a, const char *path_b)
{
printf("\n=== test_two_files ===\n");
int fd_a = open(path_a, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd_a < 0) { perror("open A"); return 1; }
int fd_b = open(path_b, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd_b < 0) { perror("open B"); return 2; }
printf("fd_a=%d fd_b=%d\n", fd_a, fd_b);
/* 分别写入不同内容 */
const char *data_a = "File-A: Hello World!";
const char *data_b = "File-B: Goodbye World!";
if (write(fd_a, data_a, strlen(data_a)) < 0) { perror("write A"); return 3; }
if (write(fd_b, data_b, strlen(data_b)) < 0) { perror("write B"); return 4; }
printf("write A: %s\n", data_a);
printf("write B: %s\n", data_b);
/* 各自 seek 回头读取,验证内容互不干扰 */
lseek(fd_a, 0, SEEK_SET);
lseek(fd_b, 0, SEEK_SET);
char buf_a[64] = {0};
char buf_b[64] = {0};
ssize_t r_a = read(fd_a, buf_a, sizeof(buf_a));
ssize_t r_b = read(fd_b, buf_b, sizeof(buf_b));
printf("read A: %zd bytes: %.*s\n", r_a, (int)r_a, buf_a);
printf("read B: %zd bytes: %.*s\n", r_b, (int)r_b, buf_b);
int ok = 1;
if (strncmp(buf_a, data_a, strlen(data_a)) != 0) {
printf("FAIL: A content mismatch!\n"); ok = 0;
}
if (strncmp(buf_b, data_b, strlen(data_b)) != 0) {
printf("FAIL: B content mismatch!\n"); ok = 0;
}
if (ok) printf("PASS: both files read back correctly\n");
/* 交叉写:向 A 追加,向 B 中段覆写,再各自读回验证 */
lseek(fd_a, 0, SEEK_END);
write(fd_a, "[A-TAIL]", 8);
lseek(fd_b, 8, SEEK_SET); /* "File-B: " 之后 */
write(fd_b, "Hi! ", 7); /* 覆写 "Goodbye" */
lseek(fd_a, 0, SEEK_SET);
lseek(fd_b, 0, SEEK_SET);
memset(buf_a, 0, sizeof(buf_a));
memset(buf_b, 0, sizeof(buf_b));
r_a = read(fd_a, buf_a, sizeof(buf_a));
r_b = read(fd_b, buf_b, sizeof(buf_b));
printf("after cross-write:\n");
printf(" A: %.*s\n", (int)r_a, buf_a);
printf(" B: %.*s\n", (int)r_b, buf_b);
close(fd_a);
close(fd_b);
unlink(path_a);
unlink(path_b);
return 0;
}
static int test_write_file(const char *path)
{
printf("\n=== test_write_file ===\n");
int fd = open(path, O_CREAT | O_RDWR, 0644);
if (fd < 0) { perror("open"); return 1; }
printf("open: %s fd=%d\n", path, fd);
const char *msg = "Hello, zvfs!";
ssize_t w = write(fd, msg, strlen(msg));
if (w < 0) { perror("write"); close(fd); return 2; }
printf("write: %zd bytes: %s\n", w, msg);
close(fd);
printf("close: ok\n");
return 0;
}
static int test_read_delete_file(const char *path)
{
printf("\n=== test_read_delete_file ===\n");
int fd = open(path, O_RDONLY);
if (fd < 0) { perror("open"); return 1; }
printf("open: %s fd=%d\n", path, fd);
char buf[256] = {0};
ssize_t r = read(fd, buf, sizeof(buf));
if (r < 0) { perror("read"); close(fd); return 2; }
printf("read: %zd bytes: %.*s\n", r, (int)r, buf);
close(fd);
printf("close: ok\n");
if (unlink(path) != 0) { perror("unlink"); return 3; }
printf("unlink: ok\n");
return 0;
}
/* ------------------------------------------------------------------ */
/* main */
/* ------------------------------------------------------------------ */
int main(int argc, char **argv)
{
int rc = 0;
char path[256];
char path_a[256];
char path_b[256];
if(argc >= 2){
sprintf(path, "%s/file.dat", argv[1]);
sprintf(path_a, "%s/file_a.dat", argv[1]);
sprintf(path_b, "%s/file_a.dat", argv[1]);
}else {
sprintf(path, "/tmp/test.dat");
}
if(argc == 3){
int choose = atoi(argv[2]);
if(choose == 0){
rc = test_write_file(path);
}else if(choose == 1){
rc = test_read_delete_file(path);
}
return rc;
}
// printf("argv[0]: %s\n", argv[0]);
// printf("argv[1]: %s\n", argv[1]);
// printf("path_a: %s\n", path_a);
// printf("path_b: %s\n", path_b);
// rc |= test_basic(path);
// 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);
printf("\n=== all tests %s ===\n", rc == 0 ? "PASSED" : "FAILED");
return rc;
}