图库: 阅读器两级清晰度,先低档上屏、停稳再换清晰(M31)
真机 1280x2275 单页解码 392ms,首次看某页有一瞬加载感。改成: - 大页(JPEG ≥1MP)先按显示长边一半的档位(真机页=step 4)解一版低档, 精确落到显示框后立刻上屏(换图仍是单次原生 blit,不闪白、不重置缩放/滚动); - 停稳 200ms 后才解目标档位(step 2),在**同一槽**原地替换低档,低档随即释放, 常驻不翻倍;高档失败/预算跳过时保留低档,不把整页标成「内存不足」; - 拖动/连翻/条漫滚动/跳页在途期间只解低档;高档请求复用 M22 的 gen/窗口 stale 判据作废(只多一条 sharpen 谓词),出队前/后两条路径都计入取消; - 日志尾部新增 tier=low|high(取消行同),真机可直接核对先糊后清。 分档只给 JPEG:step 是 JPEG 缩解概念,PNG/BMP 后端按目标逐行丢行本来就不慢, 且峰值模型对非 JPEG 按「输出=显示框」建模,多一条小图→落框路径会让模型低估 (不新增解码路径,也不改 sdk/ 与 page_source 的唯一模型)。 宿主回归: - test_reader_membudget B10:JPEG 低档先落位(open 不阻塞)→ 高档落同槽 (槽内字节不变、槽位全程不空)→ 拖动中强塞的高档请求被取消且不被解码; - B8 连翻 100 页(6 类 1.3–12MP 循环)峰值增量 2714KB ≤3MB、常驻 ≤3MB, 低档/高档都确实跑过;B3 断言小页保持单档(不付两次解码); - test_reader_perf P11:非 JPEG 大页不分档,仍是一次原生 blit。
This commit is contained in:
1 parent
ce34974727
commit
62826e1d13
4 files changed
+513
-51
No files matched your search
@@ -17,7 +17,10 @@
|
||||
* B7b 回退路径:CMYK / Adam7 PNG / 1bpp BMP 走 stb,按旧门控占位
|
||||
* B7c P1-1 旁路回归:截断 12MP JPEG / 3000×3000 24bpp 头-only BMP(判定 backend,
|
||||
* 后端失败必须 NULL、峰值 ≤3MB)/ 非法位深 PNG(矩阵拒绝→stb 占位)
|
||||
* B8 M27:连翻 30 页(6 类循环)不掉页、不占位、任何时刻存活增量 ≤3MB
|
||||
* B8 M27/M31:连翻 100 页(6 类循环)不掉页、不占位、任何时刻存活增量 ≤3MB;
|
||||
* 分档页低档/高档都确实跑过(M31:先低后清不把峰值/常驻翻倍)
|
||||
* B10 M31:两级清晰度生命周期(JPEG 大页):低档先落位(open 不阻塞)→ 停稳后高档落
|
||||
* 同一槽(槽内字节不变、槽位不空)→ 拖动中强塞的高档请求被取消通道作废
|
||||
* B9 M27:CMYK 回退页集成 —— 占位可重试且不崩
|
||||
*
|
||||
* 夹具:BMP/PNG 小夹具由本文件用 C 写;JPEG/PNG/BMP 大夹具由 python3+Pillow 生成
|
||||
@@ -591,6 +594,9 @@ int main(void)
|
||||
mr_reader_ui_failed_pages());
|
||||
/* 取消/预取纪律:100 次翻页的解码次数必须有界(M20 实测曾 1.75× 浪费)。 */
|
||||
CHECK(decodes <= 100 * 2, "decode count bounded over 100 flips (%d)", decodes);
|
||||
/* M31:小页(480×640=0.3MP)不分档——低档只会多一次解码 + 落框,纯开销。 */
|
||||
CHECK(mr_reader_ui_low_decodes() == 0,
|
||||
"small pages stay single-tier (%d low decodes)", mr_reader_ui_low_decodes());
|
||||
meow_view_page_pop();
|
||||
pump_ms(200);
|
||||
}
|
||||
@@ -762,7 +768,10 @@ int main(void)
|
||||
printf(" SKIP jpeg assertions: Pillow unavailable (python3 -c 'import PIL')\n");
|
||||
}
|
||||
|
||||
/* ---- B8 M27:连翻 30 页(6 类典型页循环)——不掉页、不占位、峰值 ≤3MB ---- */
|
||||
/* ---- B8 M27/M31:连翻 100 页(6 类典型页循环)——不掉页、不占位、峰值不增长 ----
|
||||
* M31 起这些 1.3–12MP 的页走两级清晰度(低档先上屏、停稳换高档),所以这条同时是
|
||||
* 「分档不把峰值/常驻翻倍」的回归:低档与高档在同一槽原地替换,任何时刻的存活增量
|
||||
* 仍按单页解码峰值封顶。 */
|
||||
if (have_jpeg && mixed_pages == 30) {
|
||||
mr_reader_ui_test_set_mem(4096, 16000);
|
||||
mr_reader_open_dir(mixed);
|
||||
@@ -772,11 +781,12 @@ int main(void)
|
||||
int advanced = 0, skipped_max = 0;
|
||||
size_t live_steady = g_live;
|
||||
int d0 = mr_reader_ui_decode_count();
|
||||
int low0 = mr_reader_ui_low_decodes(), high0 = mr_reader_ui_high_decodes();
|
||||
/* P2-3:只在窗口稳定后 reset 一次,之后不再 reset——这样淘汰旧图不会掩盖
|
||||
* 「分配新图 + 解码」的真实峰值;指标 = 整个 30 翻窗口内相对稳态基线的最大存活增量。
|
||||
* 「分配新图 + 解码」的真实峰值;指标 = 整个 100 翻窗口内相对稳态基线的最大存活增量。
|
||||
* (旧实现每翻页 reset 一次,淘汰把基线拉低,报告里的 536KB 是伪值。) */
|
||||
size_t base = peak_reset();
|
||||
for (int i = 0; i < 30; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int before = mr_reader_ui_page();
|
||||
tap(i % 2 == 0 ? 40 : w - 40, 300);
|
||||
pump_ms(220);
|
||||
@@ -785,20 +795,117 @@ int main(void)
|
||||
skipped_max = mr_reader_ui_skipped_pages();
|
||||
}
|
||||
size_t transient = g_peak > base ? g_peak - base : 0;
|
||||
INFO("30 mixed flips: advanced=%d skipped=%d decodes=%d steady=%zuKB "
|
||||
INFO("100 mixed flips: advanced=%d skipped=%d decodes=%d (low=%d high=%d) steady=%zuKB "
|
||||
"resident=%ldKB max_live_delta=%zuKB",
|
||||
advanced, skipped_max, mr_reader_ui_decode_count() - d0,
|
||||
mr_reader_ui_low_decodes() - low0, mr_reader_ui_high_decodes() - high0,
|
||||
live_steady / 1024, mr_reader_ui_resident_kb(), transient / 1024);
|
||||
CHECK(advanced == 30, "30 页全部翻到 (%d/30)", advanced);
|
||||
CHECK(advanced == 100, "100 页全部翻到 (%d/100)", advanced);
|
||||
CHECK(skipped_max == 0, "典型页连翻无占位 (max=%d)", skipped_max);
|
||||
CHECK(mr_reader_ui_failed_pages() == 0, "无永久失败页 (%d)",
|
||||
mr_reader_ui_failed_pages());
|
||||
CHECK(mr_reader_ui_low_decodes() > low0 && mr_reader_ui_high_decodes() > high0,
|
||||
"大页确实走了两级(low +%d, high +%d)",
|
||||
mr_reader_ui_low_decodes() - low0, mr_reader_ui_high_decodes() - high0);
|
||||
CHECK(mr_reader_ui_resident_kb() <= mr_reader_ui_resident_cap_kb(),
|
||||
"常驻仍在上限内 (%ldKB ≤ %ldKB)", mr_reader_ui_resident_kb(),
|
||||
mr_reader_ui_resident_cap_kb());
|
||||
CHECK(transient <= 3 * 1024 * 1024,
|
||||
"30 页连翻任何时刻存活增量 ≤3MB (%zuKB)", transient / 1024);
|
||||
"100 页连翻任何时刻存活增量 ≤3MB (%zuKB)", transient / 1024);
|
||||
meow_view_page_pop();
|
||||
pump_ms(200);
|
||||
}
|
||||
|
||||
/* ---- B10 M31:两级清晰度生命周期(2000×3000 JPEG,真机同类大页)----
|
||||
* 1) 冻结停稳窗口 → 只解低档:焦点页 tier=low、常驻=显示框大小(仍是一次原生 blit),
|
||||
* 主线程不等解码(open 立即返回);
|
||||
* 2) 放开停稳窗口 → 高档落同一槽:tier=high、槽内字节不变(不翻倍常驻)、槽位全程不空;
|
||||
* 3) 拖动中强塞的高档请求 → 被 M22 的 gen/窗口取消通道作废(skip=cancel),不会被解出来。 */
|
||||
if (have_jpeg) {
|
||||
char tierbook[MR_PATH_MAX];
|
||||
snprintf(tierbook, sizeof tierbook, "%s/tier", root);
|
||||
int tier_ok = mkdir_p(tierbook) == 0;
|
||||
for (int i = 0; tier_ok && i < 2; i++) {
|
||||
char src[MR_PATH_MAX], dst[MR_PATH_MAX];
|
||||
snprintf(src, sizeof src, "%s/base2000.jpg", jpgbook);
|
||||
snprintf(dst, sizeof dst, "%s/t%d.jpg", tierbook, i + 1);
|
||||
if (copy_file(src, dst) != 0) tier_ok = 0;
|
||||
}
|
||||
if (tier_ok) {
|
||||
mr_reader_ui_test_set_mem(4096, 16000);
|
||||
mr_reader_ui_test_set_sharpen_ms(60000); /* 冻结:先验证低档先落位 */
|
||||
uint64_t t_open = (uint64_t)meow_ui_time_ms();
|
||||
mr_reader_open_dir(tierbook);
|
||||
uint64_t open_ms = (uint64_t)meow_ui_time_ms() - t_open;
|
||||
CHECK(mr_reader_ui_count() == 2, "tier book pages=%d", mr_reader_ui_count());
|
||||
CHECK(open_ms < 500, "open is non-blocking (%llu ms)",
|
||||
(unsigned long long)open_ms);
|
||||
pump_ms(800);
|
||||
meow_ui_paint_full();
|
||||
int page0 = mr_reader_ui_page();
|
||||
CHECK(mr_reader_ui_focus_tier() == MR_TIER_LOW,
|
||||
"low tier lands first (tier=%d)", mr_reader_ui_focus_tier());
|
||||
CHECK(mr_reader_ui_low_decodes() >= 1, "low decode issued (%d)",
|
||||
mr_reader_ui_low_decodes());
|
||||
CHECK(mr_reader_ui_high_decodes() == 0,
|
||||
"no high decode before the settle window (%d)", mr_reader_ui_high_decodes());
|
||||
long low_kb = mr_reader_ui_slot_kb(page0);
|
||||
CHECK(low_kb > 0, "low tier image resident (%ldKB)", low_kb);
|
||||
int bl = mr_reader_ui_blit_draws(), sc = mr_reader_ui_scaled_draws();
|
||||
meow_ui_paint_full();
|
||||
CHECK(mr_reader_ui_blit_draws() > bl && mr_reader_ui_scaled_draws() == sc,
|
||||
"low tier draws as native blit (blit +%d, scaled +%d)",
|
||||
mr_reader_ui_blit_draws() - bl, mr_reader_ui_scaled_draws() - sc);
|
||||
|
||||
/* 放开升级:边等边采样,焦点槽任何时刻都不能空(不闪白)。 */
|
||||
int high0 = mr_reader_ui_high_decodes();
|
||||
long min_slot = low_kb;
|
||||
mr_reader_ui_test_set_sharpen_ms(0);
|
||||
for (int i = 0; i < 100 && mr_reader_ui_focus_tier() != MR_TIER_HIGH; i++) {
|
||||
pump_ms(10);
|
||||
long k = mr_reader_ui_slot_kb(page0);
|
||||
if (k > 0 && k < min_slot) min_slot = k;
|
||||
}
|
||||
meow_ui_paint_full();
|
||||
CHECK(mr_reader_ui_page() == page0, "tier swap keeps the page (%d -> %d)",
|
||||
page0, mr_reader_ui_page());
|
||||
CHECK(mr_reader_ui_focus_tier() == MR_TIER_HIGH,
|
||||
"high tier replaces low in the same slot (tier=%d)",
|
||||
mr_reader_ui_focus_tier());
|
||||
CHECK(mr_reader_ui_high_decodes() > high0,
|
||||
"high decode issued after settle (%d -> %d)", high0,
|
||||
mr_reader_ui_high_decodes());
|
||||
long high_kb = mr_reader_ui_slot_kb(page0);
|
||||
CHECK(high_kb > 0 && high_kb <= low_kb + 8,
|
||||
"same-slot swap: one page resident, not two (%ldKB -> %ldKB)", low_kb,
|
||||
high_kb);
|
||||
CHECK(min_slot > 0, "no blank frame while swapping tiers (min slot %ldKB)",
|
||||
min_slot);
|
||||
CHECK(mr_reader_ui_scaled_draws() == sc,
|
||||
"high tier still native blit (scaled %d -> %d)", sc,
|
||||
mr_reader_ui_scaled_draws());
|
||||
|
||||
/* 拖动中取消高档:拖动期间强塞一个「换清晰」请求,必须被取消通道作废。 */
|
||||
int hd0 = mr_reader_ui_high_decodes(), hc0 = mr_reader_ui_high_canceled();
|
||||
reader_on_touch_down(240, 400);
|
||||
reader_on_touch_move(180, 400); /* 进入拖动 → g_sharpen_idx=-1 */
|
||||
CHECK(mr_reader_ui_sharpen_idx() == -1, "drag clears sharpen eligibility");
|
||||
mr_reader_ui_test_queue_high(page0);
|
||||
pump_ms(200);
|
||||
CHECK(mr_reader_ui_high_canceled() > hc0,
|
||||
"high request canceled while dragging (%d -> %d)", hc0,
|
||||
mr_reader_ui_high_canceled());
|
||||
CHECK(mr_reader_ui_high_decodes() == hd0,
|
||||
"canceled high request is never decoded (%d -> %d)", hd0,
|
||||
mr_reader_ui_high_decodes());
|
||||
reader_on_tap(240, 400); /* 松手:回弹,不翻页 */
|
||||
pump_ms(300);
|
||||
mr_reader_ui_test_set_sharpen_ms(200); /* 恢复产品默认停稳窗口 */
|
||||
meow_view_page_pop();
|
||||
pump_ms(200);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- B9 M27:回退路径集成 —— CMYK 页占位(可重试)且不崩 ---- */
|
||||
if (have_fallback) {
|
||||
mr_reader_ui_test_set_mem(4096, 16000);
|
||||
|
||||
Reference in new issue
Block a user