Files
MeowOS c0f7a95719 feat(font+sys): 字库内存纪律(agent-215)+sysui接管launcher监管(agent-216)
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早启动与选单共存为真机重点观察项
2026-08-31 13:28:07 +08:00

120 lines
4.8 KiB
C
Raw Permalink 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.
/*
* 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;
}