/* test/font_resolve_bench.c — M31 字体路径记忆化耗时对比(宿主,不依赖设备)。 * * 同一棵树两种口径: * walk = 每次都重扫(= 加缓存前的 resolve_font 行为),由 font_cache_invalidate() 强制; * hit = 缓存命中 + access() 校验(= 加缓存后开书路径)。 * 用法:./font_resolve_bench_host [目录] [迭代数],不传目录则先造一棵 35 目录的树。 */ #include "font_resolve.h" #include #include #include #include #include #include static void mkdirs(const char *path) { char t[512]; snprintf(t, sizeof t, "%s", path); for (char *p = t + 1; *p; p++) { if (*p == '/') { *p = 0; mkdir(t, 0755); *p = '/'; } } mkdir(t, 0755); } static void write_file(const char *path, const char *body) { FILE *f = fopen(path, "wb"); if (!f) return; fputs(body, f); fclose(f); } static void make_fonts_tree(const char *root, int ndirs, int files_per_dir) { char p[512]; for (int i = 0; i < ndirs; i++) { snprintf(p, sizeof p, "%s/family_%02d/sub", root, i); mkdirs(p); for (int j = 0; j < files_per_dir; j++) { snprintf(p, sizeof p, "%s/family_%02d/readme_%d.txt", root, i, j); write_file(p, "x"); } snprintf(p, sizeof p, "%s/family_%02d/sub/Font%02d.ttf", root, i, i); write_file(p, "x"); } } static double ms_now(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (double)ts.tv_sec * 1000.0 + (double)ts.tv_nsec / 1e6; } typedef struct stat_res { double min, avg, max; } stat_res; static stat_res run(const char *root, int iters, int invalidate_each) { stat_res r = { 1e9, 0, 0 }; double sum = 0; for (int i = 0; i < iters; i++) { if (invalidate_each) font_cache_invalidate(); double t0 = ms_now(); (void)font_resolve(root); double dt = ms_now() - t0; if (dt < r.min) r.min = dt; if (dt > r.max) r.max = dt; sum += dt; } r.avg = iters ? sum / (double)iters : 0; return r; } int main(int argc, char **argv) { const char *root = (argc > 1) ? argv[1] : NULL; int iters = (argc > 2) ? atoi(argv[2]) : 200; char tmpbuf[512] = { 0 }; if (!root) { const char *base = getenv("TMPDIR"); if (!base || !base[0]) base = "/tmp"; snprintf(tmpbuf, sizeof tmpbuf, "%s/fontbench_XXXXXX", base); if (!mkdtemp(tmpbuf)) { printf("mkdtemp 失败\n"); return 2; } make_fonts_tree(tmpbuf, 35, 3); root = tmpbuf; } /* 预热(首轮含 dentry 冷缓存,不计入) */ font_cache_invalidate(); font_resolve(root); font_resolve(root); const char *p = font_resolve(root); printf("root=%s\n", root); printf("font=%s\n", p ? p : "(none)"); stat_res w = run(root, iters, 1); /* 每次失效 = 旧行为:每次开书重 walk */ stat_res h = run(root, iters, 0); /* 缓存命中 + access 校验 = 新行为 */ printf("walk (每次重扫): min=%.3f avg=%.3f max=%.3f ms\n", w.min, w.avg, w.max); printf("hit (缓存+access): min=%.3f avg=%.3f max=%.3f ms\n", h.min, h.avg, h.max); if (h.avg > 0) printf("提速: %.1fx\n", w.avg / h.avg); if (tmpbuf[0]) { char cmd[600]; snprintf(cmd, sizeof cmd, "rm -rf '%s'", tmpbuf); if (system(cmd) != 0) { /* 忽略 */ } } return 0; }