perf(reader): M32 r2 书架索引改 level-1 校验 — 真机冷缓存首开 3.47s→0.13–0.16s(r1 全目录校验被真机证伪)
r1 用宿主 1.1µs/stat + M28 的**热** stat 150µs 外推「434 次≈65ms」,真机 drop_caches 后 实测是 3.15s(7.26ms/次),与 readdir 的 3.0s 同量级:全目录校验的索引命中冷启动仍要 3.06s,只比全扫快 0.2s。「3.0s→0.15s」在冷启动不成立。按任务 1 自己定的判据 (stat 接近 1s 就退回 level-1)改为只校验 Books 根 + 每个一级目录。 真机冷缓存实测(exFAT /usr/data/mnt/sd_0,434 目录/646 文件/595 本;sync + drop_caches; 探针走 /proc/uptime,UI 走 meow_ui_time_ms): - 索引命中首开:**127 / 138 / 157ms**(复测 147ms),热 dentry 107–120ms; - 全量扫描首开:**3428 / 3477ms**(复测 3711ms),热 dentry 不变(readdir 不吃 page cache); - 探针冷分项:索引载入 20–30ms;载入+rdprog×595 70–120ms;4 个目录 stat 0–30ms; - 从阅读页返回书架 29–31ms(M29 语义未变)。 → 冷启动 22–26 倍提升,方案值得做;索引实测 **63,579B**(v2;r1 全目录 97,490B)。 实现(格式 v2,magic MEOWIDX2 / version 2): - writer 回调过滤 rel 含 '/' 的目录:只落 root + 一级目录的 mtime;书/大小/格式记录仍全量; level-2+ 不落盘、载入不 stat。载入仍然 0 次 opendir/readdir(strace:0 getdents64, 真实库 4 次 stat;宿主模拟库 11 次)。 - 校验记录里出现 level-2+ rel 视为坏档;sum(books_here) 改为「≤ nbooks」合理性上界。 - fail-open/原子写/CRC/安全加固/ts 不缓存全部保留(r1 已过评审的部分未动)。 失效矩阵(报文逐条写清): 自动(根 mtime):Books 根下直接增/删/改名书;一级目录新增/删除/改名。 自动(一级目录 mtime):一级目录里直接增/删/改名书、新建子目录。 必须刷新:level-2 及更深处的任何变化(只改深层目录 mtime)。刷新=删索引+全扫。 真机 exFAT mtime 实测 **1 秒**(tm_nsec=0;同秒连续增删 mtime 不变)。我复测 10 轮 「目录刚改过就扫描、同秒再改」→ 9/10 仍命中(陈旧),与评审 29/30 一致;sleep 跨秒后 全部正常失效。头注释已把「10ms」改为「1 秒」,并写明「不在同一秒刻度的变更靠索引失效, 同秒二次变更需刷新」。 bench 修复(P3-3):MEOW_BENCH_IDX=only —— **不预先 load/scan**,直接进书架量生产首开; miss —— 先删索引再进书架。两者配合 drop_caches 即冷启动口径。旧行为(先 bench_index/ bench_scan 焐热)保留为默认模式。新增 test/shelf_index_probe_mipsel(write/scan/load/ loadts/statpaths/mtime/size)用于真机分项与 mtime 粒度验证,不进发行包。 测试:shelf_index_smoke 170 pass(新增:level-3/level-2 内变更「索引仍命中且先看到旧 列表 → 刷新后可见」、新建 level-2 目录自动失效、一级目录直接删书自动失效、v2 ndirs= 根+一级数);ASan+UBSan 干净;build_reader.sh 0 warning,core 6846 / seg 19 / chapter 71 / shelf_group 63 / index 170 / font 14 / loaders PASS。真机 6 场景逐项验证:一级直接增/ 新建子目录/一级改名/根下删书/一级直接删书 = 自动失效;level-3 深处新增 = 仍命中(需刷新)。 交付:app.json 0.1.5/code6 → **0.1.6/code7**;reader md5 5c848c99… 1,711,988B; mpk md5 10d676f5… 814,574B;未签名不 push。设备验证后已清理 /tmp 与 m32probe, 真实 MeowData 的 shelf.idx 已删(app 自己的章节 .idx 未动),Books 434/646 不变, 已装 0.1.4 md5 4036b889… 未变。
This commit is contained in:
1 parent
e0dfab95c3
commit
58f2d9bff4
10 files changed
+309
-57
No files matched your search
@@ -23,9 +23,11 @@
|
||||
* M31:置顶时一并重算这本的副题(shelf_fmt_sub),「· 读」立即出现,不等下一次全量刷新;
|
||||
* 顶栏「刷新」同时丢弃字体路径缓存(新拷入的字库此时生效)。
|
||||
* M32:书架索引落盘(app/shelf_index.c)。冷启动先试 `MeowData/os.meow.reader/index/shelf.idx`:
|
||||
* 版本/CRC/root 路径/全部目录 mtime 校验通过 → 直接出书,**完全跳过 readdir**
|
||||
* (真机全量扫描 3.0s 的 96% 是 434 个目录的 opendir+readdir;校验只做 434 次 stat);
|
||||
* 任何异常 → 照常全量重扫(fail-open)。扫描完成后原子写回索引(写失败只丢缓存,不影响书架)。
|
||||
* 版本、CRC、root 路径、**Books 根 + 一级目录** 的 mtime 校验通过 → 直接出书,**完全跳过 readdir**。
|
||||
* 真机冷缓存实测 434 个目录逐个 stat 要 3.15s(与 readdir 同量级),所以只校验
|
||||
* 根 + 一级目录(4 次 stat ≈20ms);代价是 level-2 及更深处的变更不会自动失效,
|
||||
* 需点「刷新」(与 M29「新书靠刷新」同一约定)。任何异常 → 照常全量重扫(fail-open)。
|
||||
* 扫描完成后原子写回索引(写失败只丢缓存,不影响书架)。
|
||||
* M29 语义不变:首次进书架=索引或全扫;从阅读页返回=不扫;顶栏「刷新」=清索引+全扫。
|
||||
*/
|
||||
#include "../reader_internal.h"
|
||||
@@ -122,7 +124,8 @@ static void scan_books_full(void)
|
||||
{
|
||||
const char *dir = READER_SD_ROOT "/Books";
|
||||
shelf_scan_report rep;
|
||||
/* 扫描时把每个目录的 mtime 直接流进索引临时文件,不占额外内存、也不二次 readdir。 */
|
||||
/* 扫描时把根 + 一级目录的 mtime 直接流进索引临时文件(level-2+ 由 writer 过滤掉),
|
||||
* 不占额外内存、也不二次 readdir。 */
|
||||
shelf_idx_writer *w = shelf_index_writer_open(dir);
|
||||
g_nbooks = shelf_scan_books_ex(dir, g_books, SHELF_MAX_BOOKS, shelf_ts_of, &rep,
|
||||
w ? shelf_index_writer_dir : NULL, w);
|
||||
@@ -341,7 +344,8 @@ static void shelf_on_enter(meow_view *v, void *ctx)
|
||||
g_group_folder = (c && strcmp(c->shelf_group, "folder") == 0) ? 1 : 0;
|
||||
/* 书架缓存:本进程只在首次进入时取一次 Books/(从阅读页返回不再重扫)。
|
||||
* M32:首次先试索引(命中=只 stat 目录,跳过 readdir);索引不可用才全量扫描。
|
||||
* 扫描/校验在真机是 3.1s / ~0.1s 的差别(exFAT 434 目录 opendir/readdir 是扫描的唯一大头)。
|
||||
* 真机冷缓存实测:全量扫描首开 3.43–3.48s,索引命中首开 0.13–0.16s(M32 r2 报文);
|
||||
* readdir 是扫描的唯一大头,而冷缓存下 434 次 stat 也要 3.15s——所以 v2 只校验根+一级。
|
||||
* 代价:进程内不再自动发现新书,需点顶栏「刷新」;跨进程重启则由索引 mtime 校验兜底。
|
||||
* M30:刚读完那本例外——promote_just_read() 只读它一个进度文件并重排,低成本置顶。
|
||||
* 提示条(超上限截断 / 超深目录)语义不变:索引里存了这两个值,载入时如实重建。 */
|
||||
|
||||
Reference in new issue
Block a user