/* test/shelf_scan_bench.c — M27 扫描/排队计时(宿主 + 设备通用,纯 C)。 * * 用法:./shelf_scan_bench [progress|noop] [轮数] * progress = 每本书调 rdprog_load(生产路径,含 rdprog_dir 的 mkdir 循环 + fopen); * noop = 不读进度(基线,只测 readdir/stat/快照)。 * 进度目录由 MEOW_DATA_DIR 决定(同 App:剥 /data → .../progress);未设则 /tmp/m27bench_data。 * 输出每轮 scan / build_rows(format+folder) 微秒,末行 RESULT 汇总 min/avg/depth_skipped。 * * ⚠ 计时精度:本工具用 /proc/uptime(整数、10ms 分辨率),因为 zig mipsel musl 的 * time64/浮点 ABI 在真机上不可用(见 patch_v2/sdk/CLOCK_ABI.md)。因此: * - 真机:适合(扫描 595 本几十 ms 量级); * - 宿主:只能看到 0us / 10ms 的粗值,不可用于亚毫秒结论;宿主请改用 clock_gettime * 另写临时程序,或直接读函数的返回值。(M27 r1 报文里的 0.4ms/1.3ms 是切换前用 * clock_gettime+double 的宿主临时版本测的,不是本工具输出的。) */ #include "shelf_model.h" #include "progress.h" #include #include #include #include static char g_cfgdir[400]; const char *meow_config_dir(void) { return g_cfgdir; } static shelf_book g_books[SHELF_MAX_BOOKS]; static shelf_row g_rows[SHELF_MAX_ROWS]; static uint64_t ts_of(const char *path) { rdprog p; return rdprog_load(path, &p) == 1 ? p.ts : 0; } /* 取时用 /proc/uptime(整数、10ms 分辨率):zig mipsel musl 的 time64 ABI 在真机上 * 会让 clock_gettime/gettimeofday 的 timespec/timeval 布局失配(见 sdk/CLOCK_ABI.md), * 且静态链接下浮点打印也不可靠 —— 全程只用整数微秒。 */ static int64_t now_us(void) { FILE *f = fopen("/proc/uptime", "r"); if (!f) return 0; long sec = 0, cs = 0; if (fscanf(f, "%ld.%ld", &sec, &cs) != 2) cs = 0; fclose(f); return (int64_t)sec * 1000000 + (int64_t)cs * 10000; } int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "用法: %s [progress|noop] [轮数]\n", argv[0]); return 2; } const char *root = argv[1]; int use_prog = (argc > 2 && strcmp(argv[2], "progress") == 0); int reps = (argc > 3) ? atoi(argv[3]) : 5; if (reps < 1) reps = 1; const char *env = getenv("MEOW_DATA_DIR"); snprintf(g_cfgdir, sizeof g_cfgdir, "%s", (env && env[0]) ? env : "/tmp/m27bench_data"); int n = 0, rows_f = 0, rows_d = 0, trunc = 0, skipped = 0; int64_t best_scan = INT64_MAX, best_build = INT64_MAX, sum_scan = 0; for (int r = 0; r < reps; r++) { shelf_scan_report rep; int64_t t0 = now_us(); n = shelf_scan_books(root, g_books, SHELF_MAX_BOOKS, use_prog ? ts_of : NULL, &rep); int64_t t1 = now_us(); rows_f = shelf_build_rows(g_books, n, 0, g_rows, SHELF_MAX_ROWS); rows_d = shelf_build_rows(g_books, n, 1, g_rows, SHELF_MAX_ROWS); int64_t t2 = now_us(); int64_t s = t1 - t0, b = t2 - t1; trunc = rep.truncated; skipped = rep.depth_skipped; sum_scan += s; if (s < best_scan) best_scan = s; if (b < best_build) best_build = b; printf("run %d: scan %lld us, build_rows(format+folder) %lld us, books=%d rows_f=%d rows_d=%d trunc=%d skip=%d\n", r + 1, (long long)s, (long long)b, n, rows_f, rows_d, rep.truncated, rep.depth_skipped); } printf("RESULT root=%s mode=%s reps=%d books=%d trunc=%d rows_format=%d rows_folder=%d " "scan_min=%lldus scan_avg=%lldus build_min=%lldus depth_skipped=%d\n", root, use_prog ? "progress" : "noop", reps, n, trunc, rows_f, rows_d, (long long)best_scan, (long long)(sum_scan / reps), (long long)best_build, skipped); return 0; }