215: meow_font.c 流式分块解码(gbk峰值40→23.5MB, 逐字节校验一致) + 多字体槽5→4+16MB驻留预算; 量化: gbk稳态驻留17.3MB vs common 4.2MB(OOM主因); meow_font.a→67113c03 meow_ui.a→223d5401 216: bootmenu让位(sysui在则start launcher让位, 不在则exec兜底) + S70预置launcher.conf enabled=1(+旧设备升级迁移); launcher崩溃可自动拉起; bootmenu 4441822d / S70 e435affc / S90 e0ace111 216注: S70早启动与选单共存为真机重点观察项
120 lines
4.8 KiB
C
120 lines
4.8 KiB
C
/*
|
||
* test_mem_trace.c — MeowOS 字库加载内存驻留量测(宿主导出单测)。
|
||
*
|
||
* 目的:精确量化 meow_font_load / meow_font_unload / meow_font_reload_tier:
|
||
* (1) load 过程中堆峰值(含 PNG 解码中间:文件缓冲 + idat + 原始扫描行 + 打包面);
|
||
* (2) load 后稳态驻留(plane + glyphs);
|
||
* (3) unload 后 live 归零(free 真正归还、无碎片驻留)。
|
||
*
|
||
* 机制:-Wl,--wrap=malloc/free/calloc/realloc 把 meow_font.c 的分配纳入统计。
|
||
* __wrap_* 用「指针→字节数」记账表精确统计 live / peak(无论 libc 是否支持 usable_size)。
|
||
*
|
||
* 用法:
|
||
* gcc -I. -O0 -g test_mem_trace.c meow_font.c -lz \
|
||
* -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=calloc -Wl,--wrap=realloc \
|
||
* -o test_mem_trace
|
||
* ./test_mem_trace <font.png> <font.idx> <tier>
|
||
* 退出码 0=全过;非 0=某断言失败。
|
||
*/
|
||
#define _GNU_SOURCE
|
||
#include "meow_font.h"
|
||
#include <stdio.h>
|
||
#include <stdint.h>
|
||
#include <stddef.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
/* ---------------- 指针→大小 记账表 ---------------- */
|
||
#define TREESZ 4096
|
||
static struct { void *p; size_t sz; } g_tab[TREESZ];
|
||
static size_t g_live = 0, g_peak = 0;
|
||
static int g_tracking = 0;
|
||
|
||
static void note_add(void *p, size_t sz) {
|
||
if (!g_tracking || !p) return;
|
||
g_live += sz;
|
||
if (g_live > g_peak) g_peak = g_live;
|
||
for (int i = 0; i < TREESZ; i++) if (!g_tab[i].p) { g_tab[i].p = p; g_tab[i].sz = sz; return; }
|
||
}
|
||
static void note_sub(void *p) {
|
||
if (!g_tracking || !p) return;
|
||
for (int i = 0; i < TREESZ; i++) {
|
||
if (g_tab[i].p == p) { g_live -= g_tab[i].sz; g_tab[i].p = NULL; g_tab[i].sz = 0; return; }
|
||
}
|
||
}
|
||
static size_t note_size(void *p) {
|
||
if (!p) return 0;
|
||
for (int i = 0; i < TREESZ; i++) if (g_tab[i].p == p) return g_tab[i].sz;
|
||
return 0;
|
||
}
|
||
|
||
void *__real_malloc(size_t n);
|
||
void *__real_calloc(size_t n, size_t s);
|
||
void *__real_realloc(void *p, size_t n);
|
||
void __real_free(void *p);
|
||
|
||
void *__wrap_malloc(size_t n) { void *p = __real_malloc(n); if (p) note_add(p, n); return p; }
|
||
void *__wrap_calloc(size_t n, size_t s) { void *p = __real_calloc(n, s); if (p) note_add(p, n * s); return p; }
|
||
void *__wrap_realloc(void *p, size_t n) {
|
||
if (!p) { void *np = __real_realloc(NULL, n); if (np) note_add(np, n); return np; }
|
||
size_t old = note_size(p);
|
||
void *np = __real_realloc(p, n);
|
||
if (np) { note_sub(p); note_add(np, n); }
|
||
else { /* realloc 失败:原指针仍有效,表项保留 */ }
|
||
(void)old;
|
||
return np;
|
||
}
|
||
void __wrap_free(void *p) { if (p) note_sub(p); __real_free(p); }
|
||
|
||
static void reset_peak(void) { g_peak = g_live; }
|
||
|
||
static int g_fail = 0;
|
||
#define CHECK(cond, msg) do { \
|
||
if (!(cond)) { g_fail++; fprintf(stderr, "FAIL: %s (live=%zu peak=%zu)\n", msg, g_live, g_peak); } \
|
||
else printf("ok : %s\n", msg); \
|
||
} while (0)
|
||
|
||
static double MiB(size_t b) { return (double)b / 1048576.0; }
|
||
static double KiB(size_t b) { return (double)b / 1024.0; }
|
||
|
||
int main(int argc, char **argv) {
|
||
if (argc < 3) { fprintf(stderr, "usage: %s <font.png> <font.idx>\n", argv[0]); return 2; }
|
||
const char *png = argv[1], *idx = argv[2];
|
||
|
||
g_tracking = 1;
|
||
reset_peak();
|
||
printf("== meow_font 内存量测(精确指针记账)==\n");
|
||
printf("png=%s idx=%s\n", png, idx);
|
||
|
||
int r = meow_font_load(png, idx);
|
||
CHECK(r == 0, "meow_font_load ok");
|
||
printf(" >> load 后稳态驻留 live = %.2f MiB (%.2f KiB)\n", MiB(g_live), KiB(g_live));
|
||
printf(" >> load 期间堆峰值 peak = %.2f MiB (%.2f KiB)\n", MiB(g_peak), KiB(g_peak));
|
||
|
||
static uint16_t fb[480 * 320];
|
||
meow_font_set_fb(480, 320, 480 * 2);
|
||
printf(" drawtext smoke...\n");
|
||
meow_font_drawtext(fb, 0, 0, "中文测试 Abc 123,", 0xFFFF, 28);
|
||
meow_font_drawtext(fb, 0, 60, "试渲染第20号 face 中文", 0xF800, 20);
|
||
printf(" drawtext 后 live = %.2f MiB\n", MiB(g_live));
|
||
|
||
/* 反复 load/unload 验证无泄漏累增(每次 load 后的 live 应一致,unload 后归零) */
|
||
size_t live_after_load[3];
|
||
for (int k = 0; k < 3; k++) {
|
||
meow_font_unload();
|
||
if (g_live != 0) { printf(" [iter %d] unload 后 live=%zu (非0! -> leak)\n", k, g_live); }
|
||
meow_font_load(png, idx);
|
||
live_after_load[k] = g_live;
|
||
}
|
||
printf(" 三次 load 后 live = %.2f / %.2f / %.2f MiB\n",
|
||
MiB(live_after_load[0]), MiB(live_after_load[1]), MiB(live_after_load[2]));
|
||
CHECK(live_after_load[0] == live_after_load[1] && live_after_load[1] == live_after_load[2],
|
||
"三轮回 load/unload 稳定(无泄漏累增)");
|
||
meow_font_unload();
|
||
printf(" >> unload 后 live = %.2f MiB (峰值 %.2f MiB)\n", MiB(g_live), MiB(g_peak));
|
||
CHECK(g_live == 0, "unload 后 live 归零(free 真正归还)");
|
||
|
||
printf("\nRESULT: %s\n", g_fail ? "FAIL" : "PASS");
|
||
return g_fail ? 1 : 0;
|
||
}
|