/* test/mem_account.c — 书桥动态内存记账(宿主,--wrap=malloc/calloc/realloc/free)。 * 目的:实测「阅读态」动态堆(书桥 + FreeType 字形缓存 + 段刮擦缓冲),给 R1 内存账。 * 用一本 ~500KB 中文书:open(索引构建)→ render 首页/中间页 → 报告 current/peak。 * 页位图(阅读 UI 持有 3×691KB)不在本 harness 内,报告里另加。 * 用法:./test/mem_account_host */ #include "book.h" #include #include #include /* --- malloc 包装跟踪 --- */ static size_t g_cur = 0, g_peak = 0; void *__real_malloc(size_t); void *__real_calloc(size_t,size_t); void *__real_realloc(void*,size_t); void __real_free(void*); static size_t alloc_size(const void *p); void *__wrap_malloc(size_t n) { void *p = __real_malloc(n); size_t sz = alloc_size(p); g_cur += sz; if (g_cur > g_peak) g_peak = g_cur; return p; } void *__wrap_calloc(size_t n, size_t sz) { void *p = __real_calloc(n, sz); size_t s = alloc_size(p); g_cur += s; if (g_cur > g_peak) g_peak = g_cur; return p; } void *__wrap_realloc(void *old, size_t n) { size_t os = old ? alloc_size(old) : 0; void *p = __real_realloc(old, n); size_t ns = alloc_size(p); g_cur = g_cur - os + ns; if (g_cur > g_peak) g_peak = g_cur; return p; } void __wrap_free(void *p) { if (p) { size_t s = alloc_size(p); g_cur -= s; } __real_free(p); } /* 用 malloc_usable_size 取实际块(glibc) */ static size_t alloc_size(const void *p) { if (!p) return 0; /* 免 glibc 头:直接用 __builtin 不可靠;用 malloc_usable_size 需声明。 */ extern size_t malloc_usable_size(void *); return malloc_usable_size((void*)p); } static void write_book(const char *path, int chapters) { FILE *f = fopen(path, "wb"); for (int c = 0; c < chapters; c++) { fprintf(f, "第%d章 测试章节标题用于排版验证\n", c + 1); for (int p = 0; p < 12; p++) fprintf(f, "第%d章第%d节:这是一段用于内存记账的中文正文,验证流式排版、FreeType 光栅与 " "页位图缓存的内存占用是否在预算内。English mixed in too.\n", c + 1, p + 1); } fclose(f); } int main(int argc, char **argv) { const char *font = (argc > 1) ? argv[1] : "/home/Aska/Project/R3ProII/font/src/MiSans-Regular.otf"; const char *txt = "/tmp/rdbook_mem.txt"; write_book(txt, 40); /* ~40 章 ≈ 几百 KB */ size_t before_open = g_peak; rd_book *b = NULL; int rc = rd_book_open(&b, txt, font, 20, 130, 480, 720, 16, 20, 62); if (rc != 0) { printf("open failed %d\n", rc); return 1; } size_t after_open = g_cur; size_t peak_open = g_peak - before_open; int np = rd_book_pages(b); int W = 480, H = 720; uint16_t *buf = (uint16_t *)malloc((size_t)W * H * 2); size_t peak0 = g_peak; rd_book_render(b, 0, buf, W * 2, 0xFFFF, 0x0000); rd_book_render(b, np / 2, buf, W * 2, 0xFFFF, 0x0000); rd_book_render(b, np - 1, buf, W * 2, 0xFFFF, 0x0000); size_t peak_render = g_peak - peak0; size_t after_render = g_cur; printf("pages=%d\n", np); printf("open : cur=%zuB peak=%zuB (%.1f KiB / %.1f KiB)\n", after_open, peak_open, after_open / 1024.0, peak_open / 1024.0); printf("render: cur=%zuB peak=%zuB (+%zuB) (%.1f KiB / %.1f KiB)\n", after_render, peak_render, peak_render, after_render / 1024.0, peak_render / 1024.0); printf("pagebuf(3x480x720x2=%zuB=%.2fMiB) in UI layer, not here\n", (size_t)W * H * 2 * 3, (double)W * H * 2 * 3 / (1024.0 * 1024.0)); free(buf); rd_book_close(b); return 0; }