Files
MeowOS-SDK/sdk/test_meow_cachegov.c
AskaEth c0396e40ce sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓
sdk/:
- 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头
  (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退;
   全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势;
   LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定;
   DSD 音频格式等)
- 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c
- 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动;
  build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径;
  meow_ui_internal.h 去除 FreeType 内部声明
- meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议)
- 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font
  自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs

examples/hello/:
- 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含)

docs / README / .gitignore:
- docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API)
- README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」
- .gitignore 补新增宿主测试二进制

验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
2026-09-04 18:05:36 +08:00

190 lines
8.1 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_meow_cachegov.c — 宿主测试:SDK meow_cachegov(A:DONTNEED L0/L1 + refault 回退)。
*
* 背景(OOM_PAGECACHE_GOVERNANCE §2/§4,③混合):A 的 DONTNEED/read_pos 热路径随 SDK 库;
* 本测试用宿主桩:
* - 真实 posix_fadvise(文件数据完整性校验:drop 后文件内容不变、drop_finished 可再读);
* - meow_log 桩捕获 "[cachegov] L1 drop off=.. len=.." 断言丢弃范围([0, read_pos-keep_hot));
* - meow_cachegov_test_set_time_ms() 注入时钟驱动 refault 滚窗回退(放大 keep_hot→降L0→关A);
* - MEOW_CACHEGOV_C_FILE 指向临时文件写入 fake C 状态,断言 download_paused/prefetch_paused。
*
* 编译(patch_v2/sdk 目录下):
* gcc -Os -Wall -Wextra -I. -Iinclude -I../meow_launcherd -c meow_cachegov.c -o /tmp/cg.o
* gcc -Os -Wall -Wextra -I. -Iinclude -I../meow_launcherd test_meow_cachegov.c /tmp/cg.o -lpthread -o test_meow_cachegov
* 运行:./test_meow_cachegov (exit 0=PASS / 1=FAIL)
*/
#define _GNU_SOURCE
#include "meow_cachegov.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
/* ---- meow_log 桩:捕获最近一条 [cachegov] 行,供断言 ---- */
static char g_last_log[512];
void meow_log(int lvl, const char *fmt, ...)
{
(void)lvl;
va_list ap; va_start(ap, fmt);
vsnprintf(g_last_log, sizeof g_last_log, fmt, ap);
va_end(ap);
printf(" [cachegov.log] %s\n", g_last_log);
}
static int log_has(const char *needle) { return strstr(g_last_log, needle) != NULL; }
static int g_pass = 0, g_fail = 0;
static void check(const char *name, int cond)
{
if (cond) { g_pass++; printf("PASS %s\n", name); }
else { g_fail++; printf("FAIL %s\n", name); }
}
/* ---- read_pos 桩:由测试驱动当前读指针 ---- */
static uint64_t g_pos;
static uint64_t fake_read_pos(void *ctx) { (void)ctx; return g_pos; }
/* 建一个 size 字节的临时文件并填充确定性内容。 */
static int make_file(const char *path, size_t size)
{
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) return -1;
for (size_t off = 0; off < size; off += 4096) {
char tmp[4096];
memset(tmp, (int)(off / 4096) & 0xFF, sizeof tmp);
size_t n = (size - off) < sizeof tmp ? (size - off) : sizeof tmp;
if (write(fd, tmp, n) != (ssize_t)n) { close(fd); return -1; }
}
close(fd);
return 0;
}
/* 校验文件内容仍为确定性模式(drop 后数据完整)。 */
static int verify_file(const char *path, size_t size)
{
int fd = open(path, O_RDONLY);
if (fd < 0) return 0;
char tmp[4096];
size_t off = 0;
int ok = 1;
while (off < size) {
size_t n = (size - off) < sizeof tmp ? (size - off) : sizeof tmp;
ssize_t r = read(fd, tmp, n);
if (r != (ssize_t)n) { ok = 0; break; }
char expect[4096];
memset(expect, (int)(off / 4096) & 0xFF, n);
if (memcmp(tmp, expect, n) != 0) { ok = 0; break; }
off += (size_t)n;
}
close(fd);
return ok;
}
int main(void)
{
char path[320], cfile[360];
snprintf(path, sizeof path, "/tmp/meow_cg_%ld.bin", (long)getpid());
snprintf(cfile, sizeof cfile, "/tmp/meow_cg_%ld.state", (long)getpid());
setenv("MEOW_CACHEGOV_C_FILE", cfile, 1);
unlink(path); unlink(cfile);
const size_t size = 1024u * 1024u; /* 1MB 测试文件 */
check("make_file", make_file(path, size) == 0);
/* 1) cfg:默认 + set/get 往返 */
struct meow_cachegov_cfg c = {0};
meow_cachegov_get_cfg(&c);
check("cfg default enabled", c.enabled == 1);
check("cfg default keep_hot=256KB", c.keep_hot_bytes == 256u * 1024u);
struct meow_cachegov_cfg c2 = c;
c2.keep_hot_bytes = 128u * 1024u;
c2.drop_mode = 1;
c2.refault_backoff = 2;
check("set_cfg", meow_cachegov_set_cfg(&c2) == 0);
meow_cachegov_get_cfg(&c);
check("get_cfg roundtrip", c.keep_hot_bytes == 128u * 1024u && c.drop_mode == 1 && c.refault_backoff == 2);
/* 2) L1 drop:read_pos=512KB、keep_hot=128KB → drop [0, 384KB) off=0 len=384KB */
check("register", meow_cachegov_register(path, size, fake_read_pos, NULL) == 0);
g_pos = 512u * 1024u;
meow_cachegov_tick();
check("L1 drop off=0 len=384KB", log_has("L1 drop") && strstr(g_last_log, "off=0 len=393216"));
check("L1 range bounded by read_pos-keep_hot (no L2)",
!strstr(g_last_log, "off=393216") && strstr(g_last_log, "len=393216"));
/* 3) L1 推进:read_pos=800KB → drop [384KB, 800-128KB=672KB) off=384KB len=288KB */
g_pos = 800u * 1024u;
meow_cachegov_tick();
check("L1 drop off=384KB len=288KB", log_has("L1 drop") && strstr(g_last_log, "off=393216") && strstr(g_last_log, "len=294912"));
/* 4) refault 回退档1(放大 keep_hot 翻倍):3 次触发 2 次 → 0→1(每升降一档需间隔 ≥10s */
meow_cachegov_test_set_time_ms(0);
meow_cachegov_note_refault(); meow_cachegov_note_refault();
meow_cachegov_tick();
check("backoff -> 1 (refault*2)", meow_cachegov_backoff_level() == 1);
check("file intact after backoff1", verify_file(path, size));
/* 档1 且 keep_hot=128KB*2=256KB:read_pos=1000KB → drop 上界=744KB(已丢到 672KB) */
g_pos = 1000u * 1024u;
meow_cachegov_tick();
check("backoff1 L1 keep_hot enlarged (no L2)", meow_cachegov_backoff_level() == 1);
/* 5) 再 2 次(间隔 10s)→ 档2(L1 关,只 L0)→ download_paused=1 */
meow_cachegov_test_set_time_ms(11000);
meow_cachegov_note_refault(); meow_cachegov_note_refault();
meow_cachegov_tick();
check("backoff -> 2 (L1 off)", meow_cachegov_backoff_level() == 2);
g_pos = 900u * 1024u;
meow_cachegov_tick(); /* L1 off:应无新的 L1 drop 日志 */
check("level2 no L1 drop (only L0)", !log_has("L1 drop"));
check("download_paused @backoff>=2", meow_cachegov_download_paused() == 1);
/* 6) 再 2 次(间隔 10s)→ 档3(A 全关)→ prefetch_paused=1 + drop_finished 不再丢页 */
meow_cachegov_test_set_time_ms(22000);
meow_cachegov_note_refault(); meow_cachegov_note_refault();
meow_cachegov_tick();
check("backoff -> 3 (A off)", meow_cachegov_backoff_level() == 3);
check("prefetch_paused @backoff>=3", meow_cachegov_prefetch_paused() == 1);
meow_cachegov_test_set_time_ms(23000);
meow_cachegov_drop_finished(path);
check("drop_finished skip @A-off", log_has("drop_finished skip"));
check("file intact after A-off", verify_file(path, size));
/* 7) C 侧降载:write fake C state dl_pause=1;滚窗干净逐级降回 0 后 download_paused 仍 =1 */
{
FILE *f = fopen(cfile, "w");
check("write C state", f != NULL);
if (f) { fputs("cached_kb=35000\ndirty_kb=1000\ndl_pause=1\nprefetch_pause=0\n", f); fclose(f); }
}
meow_cachegov_test_set_time_ms(33000);
meow_cachegov_tick(); /* 3→2 */
meow_cachegov_test_set_time_ms(44000);
meow_cachegov_tick(); /* 2→1 */
meow_cachegov_test_set_time_ms(55000);
meow_cachegov_tick(); /* 1→0 */
check("backoff de-escalated to 0", meow_cachegov_backoff_level() == 0);
check("download_paused via C file", meow_cachegov_download_paused() == 1);
/* 8) L0 drop_finished(A 正常态):整文件 DONTNEED + 数据完整 + 注销条目 */
unlink(cfile);
meow_cachegov_register(path, size, fake_read_pos, NULL);
meow_cachegov_test_set_time_ms(66000);
meow_cachegov_drop_finished(path);
check("drop_finished L0 log", log_has("drop_finished L0"));
check("file intact after L0", verify_file(path, size));
check("unregister removes entry", meow_cachegov_unregister(path) != 0); /* 已注销 → 找不到 */
/* 9) disable 时 drop/tick 均 no-op:数据仍完整 */
c2.enabled = 0; meow_cachegov_set_cfg(&c2);
meow_cachegov_register(path, size, fake_read_pos, NULL);
g_pos = 512u * 1024u;
meow_cachegov_tick();
meow_cachegov_drop_finished(path);
check("file intact when disabled", verify_file(path, size));
unlink(path); unlink(cfile);
printf("----\n%d passed, %d failed\n", g_pass, g_fail);
return g_fail ? 1 : 0;
}