From d4867ddbe2a9a4f9691a86681f9c1bd08f306021 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Thu, 22 Oct 2026 11:03:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(algo):=20Q10=20=E5=AE=9A=E5=80=BC=E5=AE=8F?= =?UTF-8?q?=E6=94=B9=E5=8D=95=E7=B2=BE=E5=BA=A6=EF=BC=9B=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=20Flash=20=E4=BC=98=E5=8C=96=E7=B0=87=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=AD=A3=E5=AE=A1=E6=9F=A5=E6=8A=A5=E5=91=8A=E4=B8=89=E5=A4=84?= =?UTF-8?q?=E8=AF=AF=E5=88=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 影响面:一个头文件宏(App/algo/prot_set.h)+ 七份文档口径;固件行为逐位 等价,无功能变化。门禁全绿后提交,未推送。 验证链 - @build:0 错 0 警;Code 213,520 → 213,188(−332 B),RO/RW/ZI 不变。 - 真机 @test PASS:戳 fw build: Oct 22 2026 10:36:15 suite=NONE;无 [ERR]/ERROR/FAIL/Fault;708 ms 到 net init: OK;protect task start、 i104: listening on 2404、[STACK] 三面水位齐。 - 主机单测:prot_set 90/90、prot_elm 47/47、iec104 97/97。 - 等价性穷举:宏内 42 个字面量;int32 全域 ÷1024 往返 4,494,305 例零 差异;×1024 方向 20 万随机 float 零差异(×/÷1024 是 2^10 指数平移, 不产生尾数舍入)→ 定值默认值/上下限、校验和、104 上送值全部不变。 F-6 双精度软浮点(已落地) - 两个 Q10 宏去掉显式 (double)、1024.0 → 1024.0f:保护判据每 20 ms 每 元件 3 次定值读取改走 F407 单精度 FPU,不再软件模拟。 - .map 里 dflti/d2f/f2d/dfixi/fepilogue 共 300 B 消失;自研侧对双精度 helper 的引用归零。 - 更正报告归因:全库 0 处 %f(扫 App/Src/Inc/Drivers 共 173 个 .c/.h), 剩下 dadd/dmul/ddiv/depilogue/dfixul = 1,018 B 由 MicroLIB printfa.o 的 _printf_core → _fp_digits 无条件引用,只要还用 snprintf 就删不掉; 报告"把 %f 改整数刻度"没有可执行对象。 F-4 LVGL 死代码(判定不做) - 报告列的五项字节数逐字节仍准(合计 10,060 B),但没有一项有开关: 根因是 lv_draw_sw.c 的 execute_drawing() 无条件 switch 引用全部 task 类型,链接器 --remove 无从下手。 - 唯一总开关 LV_DRAW_SW_COMPLEX 被 ui_deco.c 的"浅 V"3 px 粗斜腿依赖 (斜段与其所需 mask 核心都在该开关内);2026-09-03 已实测失败并把两端 =1 固化 → UI_设计架构.md §1.4 第 7 条。 - 报告原"mask/grad 是文字与矩形绘制必经路径"证伪:字形走 blend 层 mask_buf,不经 lv_draw_sw_mask_*。 - 剩余路线需给 Lib/lvgl 打本地补丁(上限 ≈16 KB),而 Flash 仅占 22.1%、 无 OTA/双镜像预算 → 收益不抵代价;图片链同理不打补丁。 F-5 uvprojx 空 TU(降级为观察项) - 实测 326 个 .c / LVGL 201 个 / .map 零产出 127 个;但增量构建 4~5 s、 空 TU 只在全量重建或改 lv_conf.h 时才重编,且远程 CI 刻意不跑 @build。 - 报告原"编译时长 −40%"无基线记录,不复述;真要做用 Keil 原生 0,且排在任何 lv_conf.h 改动之后。 文档与台账 - 审查报告 §0.1/§0.4/§1/注册表/§5.1/§5.4/§6.4/W4 行按实测更正,补 2026-10-22 变更记录行与 F-4/F-6 记录去处行;登记簿 N-28 改写为"三项 已判定、仅剩 F-5 观察项"。 - 更正 FTL 写回缓存旧口径(sys_log_mcu.c 注释、运行与自检记录设计说明 §4.4、实机测试实施指南 §9.1):f_close 经 sync_fs → CTRL_SYNC → ftl_flush_cache 已落盘,"写另一个文件逼出脏页"不是必要条件;2026-10-02 那次"复位后写入整段丢失"根因是 dhara resume 锚错 checkpoint。 - 部署环境要求 §3.3 资源预算由 2026-09-11 快照刷新为 2026-10-22 实测, 并补 CCM 红线行(旧"SRAM 95.4%/极度紧张"的说法早已失效)。 - ram_baseline.py --update/--write、check_mem_numbers.py --write 已回填: mem-budget(SRAM1 57.4% / CCM 87.9%,阈值 92%)与 mem-numbers 转绿。 --- App/algo/prot_set.h | 10 +++++--- App/log/sys_log_mcu.c | 30 +++++++++++++++-------- docs/任务规划/登记簿.md | 2 +- docs/内存管理/RAM使用分析与优化方案.md | 4 +-- docs/内存管理/RAM预算台账.md | 2 +- docs/子系统设计/运行与自检记录设计说明.md | 2 +- docs/测试说明/实机测试实施指南.md | 14 +++++++---- docs/环境与部署/项目部署环境要求.md | 8 +++--- docs/问题记录/项目审查与优化建议报告.md | 30 ++++++++++++----------- scripts/ram_baseline.tsv | 1 + 10 files changed, 63 insertions(+), 40 deletions(-) diff --git a/App/algo/prot_set.h b/App/algo/prot_set.h index 122a6282..995b1f76 100644 --- a/App/algo/prot_set.h +++ b/App/algo/prot_set.h @@ -26,9 +26,13 @@ #include -/* Q10 定点:工程量 × 1024(与参考 2^10 口径一致) */ -#define PROT_SET_Q10(v) ((int32_t)(((double)(v)) * 1024.0)) -#define PROT_SET_FROM_Q10(v) ((float)((double)(v) / 1024.0)) +/* Q10 定点:工程量 × 1024(与参考 2^10 口径一致)。 + * 必须写成单精度:×/÷1024 只是 2^10 指数平移,float 与 double 的结果逐位相同 + * (宏里 42 个字面量 + int32 全域往返均已穷举核对),而写成 double 会把 + * MicroLIB 的软浮点拉进镜像——F407 只有单精度 FPU,本工程的保护判据每 + * 20 ms 节拍每元件要读三次定值(见 prot_elm_run),软件双精度纯属白烧。 */ +#define PROT_SET_Q10(v) ((int32_t)((float)(v) * 1024.0f)) +#define PROT_SET_FROM_Q10(v) ((float)(v) / 1024.0f) /* 定值项编号(枚举序 = RAM 数组序 = 校验和覆盖序,只增不删不改序) */ typedef enum { diff --git a/App/log/sys_log_mcu.c b/App/log/sys_log_mcu.c index 57e8b6fb..31ec693e 100644 --- a/App/log/sys_log_mcu.c +++ b/App/log/sys_log_mcu.c @@ -225,9 +225,10 @@ static int s_append(syslog_id_t id, const char *desc) { * 要对目标扇区做读-改-写 → 每条日志 2~4 次 NAND 页读写。本函数把 * 同一次排空里属于同一文件的最多 8 条合并成一次 512 B 追加写。 * **不改掉电语义**:批次仍在同一次 syslog_drain() 调用内写完并 - * f_close;close 回写目录项(另一个 LPN)会把 FTL 的单页写回缓存逼出 - * 到 NAND——该"写到不同 LPN 才刷前一脏页"的语义见 sys_log_evidence() - * 的 flush 诱导注释。落盘时机与旧实现每条 close 等价,批次不跨调用驻留 RAM。 + * f_close;close 内部 sync_fs → disk_ioctl(CTRL_SYNC) 会调 + * ftl_flush_cache() 把 FTL 的单页写回缓存刷进 NAND(nand_ftl.c)。 + * 落盘时机与旧实现每条 close 等价,批次不跨调用驻留 RAM;残余只到 + * "单次写事务进行中掉电/复位"为止(登记簿 N-22,2026-10-22 裁定暂不做)。 * 自愈重试与错误去重的判据与 s_append_rec 一致;容量不足时返回 -3 * 而不是就地 unlink——"满了就重建"必须由按条慢路径统一执行, * 否则一批 8 条会跨越多轮重建、语义说不清。 @@ -669,17 +670,25 @@ int syslog_last_epoch(syslog_id_t id, uint32_t *p_epoch) { /* * 函数功能:把一条取证行追加到 /log/wdev.log(掉电不丢;round 7 纯取证) * 入口参数:p_desc - 取证描述行(调用方已格式化;不可为 NULL) const char * - * 返回值:0 - 成功;-1 - 卷占用或写失败(证据可能回滚,不阻断判定) int + * 返回值:0 - 成功;-1 - 卷占用或写失败(本条证据丢失,不阻断判定) int * 限定条件:poller(defaultTask)上下文调用;卷锁一律 try(绝不阻塞) * 函数说明: * 为什么必须落盘:误复位后 RAM 态随复位消失、`[WD] task stall` 行经僵尸串口 * 可能丢失(2026-10-02 台架 round 3~6 绕圈的判据缺口),故证据必须落到 * **掉电不丢**的盘上,复位后经 FTP RETR 回读。 - * flush 诱导(关键):写完 wdev.log 后立刻 s_append(SYSLOG_RUN, ...) 写另一个 - * 文件——FTL 单页缓存语义为"写到**不同 LPN** 才把前一脏页刷进 NAND";没有 - * 这一步,本行证据会在约 1.7s 后的 IWDG 复位中回滚丢失(409 条里被回滚的 - * 07:56 记录即同类教训)。s_append 自行取卷锁(非递归锁),故必须在 - * vol_lock_release() **之后**调用,绝不可在持锁状态下调用。 + * 第二条写(旧称"flush 诱导"):写完 wdev.log 后立刻 s_append(SYSLOG_RUN, ...) + * 再落一条 run.log。保留理由是**多一条独立证据**(run.log 有 UI 记录页与 FTP + * 回读两个消费者),**不是持久性手段**:f_close 内部 sync_fs → + * disk_ioctl(CTRL_SYNC) 已经调 ftl_flush_cache() 把 wdev.log 的脏页刷进 NAND + * (nand_ftl.c 的 CTRL_SYNC 分支),所以"写另一个文件(不同 LPN)逼出前一脏页" + * 从来不是必要条件。 + * ⚠ 2026-10-02 round 3~8 那次"复位后写入整段丢失"的根因是 dhara resume 锚错 + * checkpoint 使 journal 整段回退(docs/架构设计/STM32F4-Base存储架构说明.md + * §5.4.1),不是这层缓存:单页缓存最多丢最后未跨页那笔(≤512 B),丢不出 + * "整段"。真正的残余(无空闲/掉电前周期 flush)= 登记簿 N-22,2026-10-22 + * 用户裁定暂不做。 + * 顺序硬约束不变:s_append 自行取卷锁(非递归锁),必须在 vol_lock_release() + * **之后**调用,绝不可在持锁状态下调用。 * 容量护栏:> 8KB 先 unlink 重建,防长跑无界增长(8.3 合法名 wdev.log)。 */ int sys_log_evidence(const char *p_desc) { @@ -732,7 +741,8 @@ int sys_log_evidence(const char *p_desc) { } vol_lock_release(); - /* flush 诱导:写另一个文件(不同 LPN)把 wdev.log 的脏页刷进 NAND。 + /* 第二条写:再落一条 run.log 作为独立证据;不是为了刷 NAND——上面的 + * f_close 已经 CTRL_SYNC 落盘(机制见本函数头"第二条写"段)。 * 必须在释放卷锁之后调用(s_append 自行取锁,非递归锁不可重入)。 */ (void)s_append(SYSLOG_RUN, "wd stall declared"); diff --git a/docs/任务规划/登记簿.md b/docs/任务规划/登记簿.md index f0114787..31916904 100644 --- a/docs/任务规划/登记簿.md +++ b/docs/任务规划/登记簿.md @@ -45,6 +45,6 @@ | N-23 残余 | **钩子已落地**(2026-10-12 `registration-check` 挂 pre-commit,存量缺口走 `KNOWN_GAPS` 白名单只 WARN);**残余** = 白名单只剩 `rs485_task.c` 一条**刻意**缺口(E-59 门禁下随 B2 暂缓,见 `暂缓-RS485.md`);`app_cfg.h` 未接线开关(C5)。⚠ `lftpd_log.c` 已随 N-19 删除并入 `lftpd_auth.c`(2026-10-11),不再是缺口 | 白名单不清 = "写了不编译"盲区仍在 | 随 B2 一并出白名单(`--strict` 供审计复跑);开关随 C5 处置 | W4(C5) | 报告 N-06 残余 + 报告 S-3 | | N-25 | 性能/资源建议簇:PASV 每次新建监听;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE(**DE 项随 B2 暂缓,见 `暂缓-RS485.md`**)。⚠ 原列的 `NET_RECV_TIMEOUT_MS 30000` 已随 2026-10-13「recv 语义主流化」删除(挂起 recv 模型),不再是待办 | 次级性能/语义一致性 | 逐项见 `../问题记录/项目审查与优化建议报告.md` §4.2/§4.7,随窗口评估 | W4 | 报告 N-09/PHY/P3-x/rs485 | | N-27 | **内存优化簇**:**R-9 ✅ 已落地(2026-10-15)**——`LV_MEM_SIZE` 40→16 KB → SRAM1 由 74.9% 降到 **56.1%(余 57,504 B)**;待迁 CCM 体量随之由 54,146 B 降到 **29,570 B**,而 CCM 只剩 **7,904 B**(`RW_CCM` 上限 65,280 − 57,376) | ⏸ **整簇暂缓(用户裁定 2026-10-15)**:R-2 后半(缩堆 56→32 KB → 迁 CCM)与 R-3 / R-4 / R-6 **不再排期**——没有功能在等这块预算,而搬迁要动 scatter、要逐条过 DMA 可达性清单、缩堆还要上板复测,收益不抵风险与工时。⚠ 代价落在"以后加任务 / 抬栈 / 加堆"那一刻:CCM 只剩 7,904 B、FreeRTOS 堆实测 `min_ever` 8,464 B,届时 `mem-budget` 会先报警 → 按报告 §5.3 重开条件评估 | **三件套 ✅ 2026-10-12 落地**(`ram_baseline.py` 四模式 + `ram_baseline.tsv` 趋势 + `docs/内存管理/RAM预算台账.md` + `mem-budget` 钩子 92% 门禁)→ **R-9 ✅ 2026-10-15**(实测峰值 6,568 B = 池的 40%,水位表见 `../内存管理/RAM使用分析与优化方案.md` §2.6.2)→ **⏸ 其余整簇暂缓**(2026-10-15 裁定;理由与重开条件 → `../问题记录/项目审查与优化建议报告.md` §5.3)。⚠ **R-5 已判定不可行、从本簇剔除**:CMSIS-RTOS2 `freertos_os2.h` 有 `#if (configMAX_PRIORITIES != 56) #error`,改小直接编译失败(为 480 B 改第三方包装层不划算) | **暂缓** | 报告 R-2 剩余/R-3/R-4/R-6/§5.5 | -| N-28 | Flash 死代码评估簇:剩余 ≈10 KB(`box_shadow` 3,246 / `draw_sw_img` 2,960 / `bin_decoder` 1,972 / `image_decoder` 952 / `triangle` 930)+ 双精度 `dadd` 等 ≈1 KB;uvprojx 仍挂 201 个空 LVGL TU(F-1/F-2/F-3 已闭环,省的是编译时长) | 编译时长 + 文档噪音 | 逐项实测再关;⚠ `mask`/`mask_rect`/`grad` 是文字与矩形绘制必经路径,**不可盲关** | W4 | 报告 F-4/F-5/F-6 | +| N-28 | **本簇三项已全部判定(2026-10-22)**:**报告 F-6 ✅ 落地**(`App/algo/prot_set.h` 两个 Q10 宏去显式 `(double)` → `@build` 0 错 0 警、Code −332 B、保护判据路径不再走软件双精度;剩余 `dadd`/`dmul`/`ddiv`/`depilogue`/`dfixul` 1,018 B 锁在 MicroLIB `printfa.o` 的 `_printf_core → _fp_digits`,**与 `%f` 无关——全库 0 处 `%f`,报告原归因错**);**报告 F-4 ❌ 判定不做**(五项字节数仍准、合计 10,060 B,但**无一项有开关**:根因是 `lv_draw_sw.c` 的 `execute_drawing()` 无条件 switch 引用全部 task 类型;唯一总开关 `LV_DRAW_SW_COMPLEX` 被主界面"浅 V"3 px 粗斜腿锁死,2026-09-03 已实测失败并两端固化 =1;报告原"mask 是文字必经路径"的理由亦证伪——字形走 blend 层 `mask_buf`) | 仅剩 **报告 F-5 🟡 观察项**:uvprojx 201 个 LVGL `.c` 里 **127 个是空 TU**(`.map` 零产出);增量构建实测 4~5 s、远程 CI 刻意不跑 `@build` → **非产品指标**,报告原"编译时长 −40%"无基线记录 | 有实测的全量构建耗时痛点时再做:用 Keil 原生 `0`(可逆)而非删条目,且排在任何 `lv_conf.h` 改动之后;动手前先补一次全量构建计时做基线 | W4 | 报告 F-4/F-5/F-6 | | N-29 | **仓库膨胀**:`.git` **235.3 MB**(2026-10-14 实测;本行建档时记 149 MB)+ 手册图片 36.3 MB(受控文件合计仅 79.3 MB,`.git` 已是它的 3 倍) | clone/备份慢,且持续恶化 | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写**(三项都不解决历史膨胀)。**已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评(届时未推送提交更少、重写代价最低) | **W7** | 报告 D-1 | | U 簇 | UI 标准化:无令牌层/组件库/页注册表(手写 `case` 仍在),**27 页**未落地;golden 未挂 pre-commit、字符集差集检查仍是约定 | 新增一页成本仍是 8 处手工改动 | 按 `../问题记录/项目审查与优化建议报告.md` §6.5:U4 残余(两脚本入门禁,可逢窗口顺带)→ U1 令牌层 → U2/U3 → 页面落地;U4 golden 可直接当 U1 验收工具。**已确认(2026-10-11):本轮不排期**,等功能主线出结果后按产品需求启动 | W6 | 报告 U1~U5 | diff --git a/docs/内存管理/RAM使用分析与优化方案.md b/docs/内存管理/RAM使用分析与优化方案.md index f5bcdd2b..a03776be 100644 --- a/docs/内存管理/RAM使用分析与优化方案.md +++ b/docs/内存管理/RAM使用分析与优化方案.md @@ -36,10 +36,10 @@ | 区域 | 用量 | 容量 | 占比 | |---|---|---|---| -| ER_IROM1 | 232,100 B (226.66 KB) | 1,048,576 B (1024 KB) | 22.1% | +| ER_IROM1 | 231,768 B (226.34 KB) | 1,048,576 B (1024 KB) | 22.1% | | RW_IRAM1 | 75,264 B (73.50 KB) | 131,072 B (128 KB) | 57.4% | | RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% | -| **Flash (ROM 合计)** | **233,284 B (227.8 KB)** | 1,048,576 B (1024 KB) | **22.2%** | +| **Flash (ROM 合计)** | **232,952 B (227.5 KB)** | 1,048,576 B (1024 KB) | **22.2%** | 各区的容量与常量来源: diff --git a/docs/内存管理/RAM预算台账.md b/docs/内存管理/RAM预算台账.md index 0ca2202b..35558c24 100644 --- a/docs/内存管理/RAM预算台账.md +++ b/docs/内存管理/RAM预算台账.md @@ -15,7 +15,7 @@ | 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) | |---|---|---|---|---| -| ER_IROM1 (Flash) | 232,100 B | 1,048,576 B | 22.1% | 参考 | +| ER_IROM1 (Flash) | 231,768 B | 1,048,576 B | 22.1% | 参考 | | RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS | | UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 | | RW_IRAM1 | 75,264 B | 131,072 B | 57.4% | PASS | diff --git a/docs/子系统设计/运行与自检记录设计说明.md b/docs/子系统设计/运行与自检记录设计说明.md index 43e79f66..6ba2a4f9 100644 --- a/docs/子系统设计/运行与自检记录设计说明.md +++ b/docs/子系统设计/运行与自检记录设计说明.md @@ -130,7 +130,7 @@ defaultTask(唯一写者,挂载成功后): ``` - **N-24(2026-10-15,报告 N-16 写侧):一次排空合并成"每文件一次 open/write/close"**。旧实现每条记录一轮,而 `f_close` 要回写目录项、`f_write` 要对目标扇区做读-改-写 → **每条日志 2~4 次 NAND 页读写**。现在同一文件的一批(≤8 条 = 512 B 静态缓冲 `s_batch`)合并成一次追加写: - - **掉电语义不变**:批次仍在**同一次 `syslog_drain()` 调用内**写完并 `f_close`;close 回写目录项(另一个 LPN)会把 FTL 的单页写回缓存逼出到 NAND——该"写到不同 LPN 才刷前一脏页"的语义见 `sys_log_evidence()` 的 flush 诱导注释。落盘时机与旧实现每条 close 等价,**批次不跨调用驻留 RAM**。 + - **掉电语义不变**:批次仍在**同一次 `syslog_drain()` 调用内**写完并 `f_close`;`f_close` 内部 `sync_fs` → `disk_ioctl(CTRL_SYNC)` 会 `ftl_flush_cache()` 把 FTL 的单页写回缓存刷进 NAND(`Drivers/BSP/GD5F2GQ5UE/nand_ftl.c` 的 `CTRL_SYNC` 分支)。落盘时机与旧实现每条 close 等价,**批次不跨调用驻留 RAM**:"写完即关"的路径关文件即落盘,残余只到"单次写事务进行中掉电/复位"为止(`../任务规划/登记簿.md` N-22:无空闲/掉电前周期 flush,2026-10-22 用户裁定暂不做)。 - **条目不丢**:启动前数组按下标"看而不删",整批成功才删;队列条目在落盘失败(-2 卷忙 / -1 写失败 / -3 容量不足)时**回投队列**——旧实现 -2 会直接丢掉那一条。 - **容量轮转仍只在按条慢路径做**:批量路径发现剩余容量装不下一批时返回 -3,退回逐条 `s_append()`("满了 unlink 重建"只保留一处实现,避免一批跨多轮重建)。 - 自愈重试(L1 丢弃重建 + 重试一次)与错误去重(L2 只报第一次)判据与单条路径一致。 diff --git a/docs/测试说明/实机测试实施指南.md b/docs/测试说明/实机测试实施指南.md index fd07c083..b971042f 100644 --- a/docs/测试说明/实机测试实施指南.md +++ b/docs/测试说明/实机测试实施指南.md @@ -367,13 +367,17 @@ CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创 - **L1 dhara checkpoint 回滚**(`架构设计/STM32F4-Base存储架构说明.md` §5.4.1):环回绕后 `dhara_journal_resume()` 恢复旧 checkpoint,**之后写的一切整段丢弃** (已修:epoch 锚点改比较两候选的新旧)。 - - **L2 FTL 单页写回缓存**:任何磁盘改动(截断/新建/追加)在**写到另一个 LPN / 另一个文件 - 或 `CTRL_SYNC`** 之前只存在于 RAM(`nand_ftl.c` 的 `s_cache_buf/s_cache_dirty`); - 硬复位(含 IWDG 误复位)会丢失最后一次未跨页的写(`N-14` 已登记;`CTRL_SYNC` 已实现, - 但**没有周期性/掉电前强制 flush**,属残余风险)。 + - **L2 FTL 单页写回缓存**:一次 `disk_write` 里不满整页(2048 B)的写,在**写到另一个 LPN / + 整页写 / `CTRL_SYNC`** 之前只存在于 RAM(`nand_ftl.c` 的 `s_cache_buf/s_cache_dirty`)。 + 但正常 `f_close` 就会走到 `CTRL_SYNC`(FatFs `sync_fs` → `disk_ioctl` → `ftl_flush_cache`), + 所以**"写完即关"的路径(日志、配置保存)关文件即落盘,不必再"写另一个文件逼刷"**;会丢的 + 只有**写事务进行中**掉电/硬复位(含 IWDG 误复位)里最后那笔未跨页的写(≤512 B)—— + FTP STOR 传输途中掉电就落在这一档(`N-14` 已登记;登记簿 N-22 于 2026-10-22 裁定暂不做, + 缺的是"空闲/掉电前周期 flush",且本机无掉电检测硬件,掉电时点无法补救)。 → 排查写入丢失时**先看开机日志的 head/tail/epoch**(`Map head=… tail=… epoch=…`, 纯内存字段、零 I/O):head 复位后倒退 = L1(resume 错);head 正常 = L2(缓存未刷)。 - 日常"清台账/写证据后写另一个文件"的 flush 诱导只对 L2 有效。 + (旧口径"清台账/写证据后写另一个文件"的 flush 诱导属 L1 时代的产物:现码 `f_close` 自带 + `CTRL_SYNC`,正常写完即关就不需要它;这条诱导只在 `f_close` 失败时才还有兜底意义。) 2. **FTP 路径**:lftpd 相对路径基准是**根目录**(`SIZE selftest.log` → 550),一律用 绝对路径 `/log/xxx`;`LIST /log` 实测列的是**根目录**内容(lftpd 怪癖)——查状态只用 `SIZE` / `RETR`。 diff --git a/docs/环境与部署/项目部署环境要求.md b/docs/环境与部署/项目部署环境要求.md index a744e3ba..bd565260 100644 --- a/docs/环境与部署/项目部署环境要求.md +++ b/docs/环境与部署/项目部署环境要求.md @@ -495,12 +495,14 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级 ### 3.3 资源预算(部署红线) -实测(2026-09-11 快照口径,现汇总于 `docs/内存管理/RAM使用分析与优化方案.md`): +实测(**2026-10-22 `@build` 快照**)。实时权威值恒以 `docs/内存管理/RAM预算台账.md` 与 +`docs/内存管理/RAM使用分析与优化方案.md` §2.1 受管快照为准,本节只是部署视角的摘要: | 资源 | 已用 | 总量 | 利用率 | 余量 | 红线说明 | |---|---|---|---|---|---| -| Flash | 232,000 B(226.6 KB) | 1 MB | 22.1% | ~798 KB | 充裕 | -| 主 SRAM(静态区+堆) | 125,104 B(122.2 KB) | 128 KB | **95.4%** | **5.8 KB** | **极度紧张**:新增任何静态缓冲/任务栈前必须先核算 RAM 余量 | +| Flash(`ER_IROM1` = Code + RO) | 231,768 B(226.3 KB) | 1 MB | 22.1% | ≈804 KB | **充裕**:产品需求无 OTA / 双镜像预算,Flash 不是卡点;死代码裁剪簇已收口 → `docs/问题记录/项目审查与优化建议报告.md` §5.4 | +| 主 SRAM1(静态区;FreeRTOS 堆已迁 CCM) | 75,264 B(73.5 KB) | 128 KB | 57.4% | 55,808 B | 已不紧张——2026-10-11 堆迁 CCM 与 2026-10-15 `LV_MEM_SIZE` 40→16 KB 两步的结果 | +| CCM(`RW_CCM` 段) | 57,376 B(56.0 KB) | 65,280 B | **87.9%** | **7,904 B** | **当前真正的红线**:加任务 / 抬栈 / 加堆会先在这里撞墙;`mem-budget` 钩子在 92% 拦提交 | - LVGL 内存池 16 KB(静态占用,2026-10-15 由 40 KB 收缩);FreeRTOS 堆 56 KB(CCM) - 任务栈预算(words,1 word = 4 B): diff --git a/docs/问题记录/项目审查与优化建议报告.md b/docs/问题记录/项目审查与优化建议报告.md index 3bf19430..79a565c4 100644 --- a/docs/问题记录/项目审查与优化建议报告.md +++ b/docs/问题记录/项目审查与优化建议报告.md @@ -27,7 +27,7 @@ | 文档分布 | **A−** | 工程文档 **87 篇 / 30,781 行**(2026-10-15 随 `错误码传播审计.md` 删除而 −1 篇 / −635 行),`docs/README.md` 索引 + `docs/文档规范.md` + 三档一致性门禁全部落地,`check_doc_links --all` = 0 失效 | **D-1**:`docs/` 占仓库 **71.8%**、手册图片 **36.3 MB**、`.git` 已 **235 MB**(已决策暂不处理,登记观察) | | 模块设计 | **A−** | 看门狗(IWDG + 心跳位图 + 4 个 Fault 现场 + `.noinit`)、就绪屏障、卷锁、FTP 鉴权、`Error_Handler` 自恢复、ADC 全链均已落地;**原列的 dhara 移植层两处缺陷(N-12/N-13)与日志逐条开关(N-16)已于 2026-10-15 修复** → `GD5F2GQ5UE_Trap_Records.md` TRAP-GD5F-07、`../架构设计/STM32F4-Base存储架构说明.md` §5.3、`../子系统设计/运行与自检记录设计说明.md` §4.4/§4.5 | 驱动层无统一错误码约定(S-5)、RS485 无协议栈(随 B2 暂缓) | | 内存使用 | **B+** | 堆迁 CCM + 栈/堆三面观测常开 + `mem-budget` 92% 门禁 + 预算台账与趋势基线;**R-9 已落地(2026-10-15)→ SRAM1 由 74.9% 降到 56.1%;同日移植层与日志修复 +1.6 KB → 现 **57.4%(余 55,840 B)**,不再是卡点** | **内存优化簇已整簇暂缓**(用户裁定 2026-10-15):R-2 后半(待迁 29,570 B → CCM,只差缩堆 56→32 KB)与 R-3 / R-4 / R-6 不再排期,理由与重开条件见 §5.3;**当前真正的约束是 CCM 只剩 7,904 B**——加任务 / 抬栈 / 加堆会先在这里撞墙,届时按 §5.3 重开;MicroLIB 512 B C 堆仍无机械检查(§5.5) | -| Flash 使用 | **A−** | F-1/F-2/F-3 落地省 64,576 B → 占用 **22.2%(232,280 B)** | F-4/F-5/F-6 ≈10 KB + 编译时长(§5.4) | +| Flash 使用 | **A−** | F-1/F-2/F-3 落地省 64,576 B;**F-6 亦已落地(2026-10-22,−332 B)→ 现 22.1%(231,768 B)**,1 MB 用两成、余 ≈800 KB,产品需求无 OTA/双镜像预算 | **F-4 判定不做、F-5 降级观察项**(实测复核见 §5.4)→ **Flash 侧已无可回收项** | | UI 标准化 | **B+** | W6 第一波已落地(2026-10-15):**L0 设计令牌层** `ui_tokens.h` 建成、**L2 页面注册表** `ui_page_registry.{c,h}` 由生成器产出并**删除了手写 `case` 分发**、`font-charset` 钩子 + `registration-check` 第 ④ 类接线校验上线、字体子集瘦身 −80 B | L1 组件库已起步(U2 首个 `ui_w_records`,2026-10-20),但仅此 1 个组件、**目标页未落地**(现存 7 个 `ui_page_*.c`)、**golden 像素回归已于 2026-10-20 挂入提交门禁**(`ui-golden`)、`ui_w_form` 推迟 U5(§6) | ### 0.3 主线建议 @@ -48,7 +48,7 @@ | 内存 RAM | **R-2 剩余** ⏸ **暂缓**(N-27,原 W3) | 待迁体量已由 54,146 B 降到 **29,570 B**(R-9 落地后);CCM 只剩 7,904 B | **用户裁定 2026-10-15:暂不做**——没有功能在等这块预算;重开条件 → §5.3 | | 内存 RAM | R-3 / R-4 / R-6 ⏸ **暂缓**(N-27,原 W3) | 页缓冲未合并 / UI 帧 4 副本 / 栈仍动态 | **同上裁定,暂不做**。本簇已落地的只有 R-9(2026-10-15,SRAM1 74.9%→56.1%,见 §5.3);**R-5 已判定不可行**(§5.3) | | 内存 RAM | N-14 🟡(N-22,W4) | 写回缓存无空闲/掉电强制 flush(整页写与换页已 flush) | 空闲 N ms 由 defaultTask flush | -| **Flash** | **F-4 / F-5 / F-6** ❌(N-28,W4) | 剩余可评估 ≈10 KB(`box_shadow` 3,246 / `draw_sw_img` 2,960 / `bin_decoder` 1,972 / `image_decoder` 952 / `triangle` 930)+ 双精度 `dadd` 等 ≈1 KB;uvprojx 仍挂 201 个 LVGL `.c`(F-2 后均为空 TU,省的是编译时长) | 逐项实测再关;⚠ `mask`/`mask_rect`/`grad` 是文字与矩形绘制的必经路径,**不可盲关** | +| **Flash** | F-5 🟡 观察项(N-28,W4) | ~~F-4~~ **判定不做**、~~F-6~~ **已落地**(2026-10-22,见 §5.4)。仅剩 uvprojx 挂 201 个 LVGL `.c`,其中 **127 个在 `.map` 里零产出**(空 TU)——只在全量重建 / 改 `lv_conf.h` 时才重编;增量构建实测 4~5 s,且远程 CI 刻意不跑 `@build` → 非产品指标 | 有实测的全量构建耗时痛点时再做:用 Keil 原生 `0`(可逆)而非删条目,且必须排在任何 `lv_conf.h` 改动之后(空 TU 集合随裁剪变化) | | **性能/资源** | N-09 / PHY / P3-x / rs485 DE ❌(N-25,W4) | PASV 每次新建监听;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE(DE 项随 B2 暂缓) | 见 §4.2 / §4.7 各行建议 | | **结构** | S-1 / S-2 / S-4 ❌ | `NETCFG`/`UI` 语义层错位;4 处裸 `extern`;`app_cfg.h` 开关未接线未删 | 随登记簿 C5 处置;`rs485_task.c` 随 B2 一并出白名单 | | **存储/日志** | N-15 🟡 / P2-10 ❌ | `nand_ftl` 三块 2 KB 页缓冲未合并(BBT 缓冲已收紧);容量轮转 `f_unlink` 与 UI 读并发未纳入卷锁 | R-3 评估;卷锁覆盖面 → 登记簿 S-5 | @@ -95,7 +95,7 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap | 术语 | 定义 | |------|------| | 自研代码 | `App/`、`Drivers/BSP/`(不含 `Lib/`、`Middlewares/`、HAL/CMSIS)、`test/`;不含 CubeMX 生成的 `Src/`、`Inc/` | -| Flash 占用 | `Code + RO-data` = `ER_IROM1` **232,280 B(22.2% of 1 MB)**;`ROM` 再加 `RW-data` 初始化表 = 233,416 B | +| Flash 占用 | `Code + RO-data` = `ER_IROM1` **231,768 B(22.1% of 1 MB,2026-10-22 构建)**;`ROM` 再加 `RW-data` 初始化表 = 232,060 B | | RAM 占用 | `RW-data + ZI-data`,**跨两个区域** = SRAM1 `RW_IRAM1` **75,232 / 131,072(57.4%)** + CCM `RW_CCM` **57,376 / 65,280(87.9%)** + `UNINIT_CCM` 48 B(`.noinit` 崩溃现场保留区)。⚠ 原报告"CCM 不在 scatter 内计 0"的口径已不成立 | | "死代码" | 该对象在镜像中有码,但其功能被工程配置(如 `LV_COLOR_DEPTH 1`)或调用点扫描(零调用者)证明不可达 | @@ -155,7 +155,7 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap |------|------|------| | **两边都不注册** | 基线 5 个 → 现剩 **1 个**:`App/task/rs485_task.c`(E-59 门禁下的**刻意**缺口,随 B2 暂缓,已登记 `KNOWN_GAPS`) | `crc.c`/`ringbuf.c` 已整体删除(全库无调用者)、`lftpd_log.c` 已删除并入 `lftpd_auth.c`、`adc_task.c` 已挂 uvprojx(仅 MCU,符合"任务层不入模拟器")——**"写了不编译"的盲区已消** | | **仅 simulator 注册** | `cfg_file_store_sim.c`、`net_socket_sim.c`、`sim_port.c`、`sim_syslog.c`、`ui_net_sink_backend_sim.c` | 正常(后端适配层模式) | -| **uvprojx** | 323 个 `.c`(含 201 个 LVGL) | LVGL 全量编译 → 编译时长;F-2 落地后未用控件类 TU 均为空目标文件(见 §5.4 F-5) | +| **uvprojx** | 326 个 `.c`(含 201 个 LVGL,其中 **127 个在 `.map` 里零产出** = 空 TU) | LVGL 全量参与编译 → 只在全量重建 / 改 `lv_conf.h` 时体现(见 §5.4 F-5) | **评价**:AGENTS.md 的"新文件必须注册两处"铁律如今**两端都有机械保障**——正向由 `new-source-file` skill 约束,反向由 `scripts/check_registration.py`(pre-commit `registration-check` 钩子,2026-10-12)校验"存在但未注册",并反向查"注册了但文件不存在"的幽灵注册。**残余只有一条刻意缺口**:`rs485_task.c` 在 `KNOWN_GAPS` 里等 B2 立项,随该簇一并处置即可(清完后把 `--strict` 设为默认)。 @@ -359,9 +359,9 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap | 其余(`App/` 应用与驱动自研、startup、C 库、填充) | ≈45,497 | ≈19.7% | | **合计** | **231,084** | 100% | -> 归类按 `.map` 组件表对象名前缀,合计与区域总量可差几十字节(链接器填充)。前 7 行逐字节与 2026-10-14 那次构建相同;并行未提交改动(`cfg_file` / `sd2506`)的 +48 B 落在"其余"。⚠ **本表是那次构建的构成快照**(合计 231,084 B);当前镜像 **232,280 B / 22.2%**,增量 +1,192 B `Code` 来自同日 dhara 移植层守卫与日志批量化(登记簿原 N-21 / N-24),**不改变"LVGL 是最大单一子系统"的结论**。 +> 归类按 `.map` 组件表对象名前缀,合计与区域总量可差几十字节(链接器填充)。前 7 行逐字节与 2026-10-14 那次构建相同;并行未提交改动(`cfg_file` / `sd2506`)的 +48 B 落在"其余"。⚠ **本表是那次构建的构成快照**(合计 231,084 B);当前镜像 **231,768 B / 22.1%**(2026-10-22 构建;快照之后的净变化含 §5.4 F-6 的 −332 B),同期增量 +1,192 B `Code` 来自同日 dhara 移植层守卫与日志批量化(登记簿原 N-21 / N-24),**不改变"LVGL 是最大单一子系统"的结论**。 -**要点**:LVGL 的绝对量自 F-1/F-2/F-3 裁剪后**未再增长**(87,706 B),但仍是镜像最大单一子系统 → §5.4 的剩余裁剪(≈10 KB)与 F-5 的编译时长收益依旧成立。 +**要点**:LVGL 的绝对量自 F-1/F-2/F-3 裁剪后**未再增长**(87,706 B),仍是镜像最大单一子系统;但**剩余部分已被结构性锁死**(§5.4 F-4 判定不做)→ LVGL 体积自此不再是可优化项。 ### 5.2 结构性诊断(三条) @@ -401,17 +401,17 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap 与 `../内存管理/RAM使用分析与优化方案.md` 的关系:本表**沿用其阶段划分**(阶段 0 测量 / 阶段 1.1 池收缩 / 阶段 1.2 CCM / 阶段 2 堆收缩),本报告新增的是 ①R-4 帧副本去重(原文档未识别 4 份副本)②R-3 存储侧缓冲合并 ③**DMA 可达性硬边界**(原报告 N-11 提出,现已沉淀为 `../内存管理/内存内容分配策略.md` §4 规则 R2/R3,属实施风险关键点)。 -### 5.4 Flash 优化(未闭环:F-4 / F-5 / F-6) +### 5.4 Flash 优化(2026-10-22 收口:F-6 已落地、F-4 判定不做、F-5 降级观察项) > **F-1 / F-2 / F-3 已落地并销项(2026-10-11)**:两份 `lv_conf.h` 对齐为同一特性子集 → **实测省 64,576 B**,Flash 26.3% → 20.1%(现 22.2%,增量来自 B4/B5 功能代码)。完整记录见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4 与 `../UI设计/UI_设计架构.md` §1.4 第 10 条。 -| 编号 | 措施 | 可省 Flash | 依据 | 状态 | +| 编号 | 措施(原建议) | 原估收益 | 实测复核(2026-10-22 逐项对 `.map`,基线 Code 213,520 / RO 18,580) | 状态与结论 | |------|------|-----------|------|------| -| **F-4** | 关闭未用的绘制子模块与 `LV_USE_SNAPSHOT`(MCU 端)/`LV_USE_OBJ_PROPERTY`/`LV_USE_FLOAT` 等 | 可评估部分 **≈10 KB** | 对象实测:`box_shadow` 3,246 + `draw_sw_img` 2,960 + `bin_decoder` 1,972 + `image_decoder` 952 + `triangle` 930 ≈ **10.1 KB**;工程无图片、无阴影、无变换 | ❌ 未办。⚠ **不可盲目关**:`mask` 3,862 / `mask_rect` / `grad` 是文字与矩形绘制的必经路径 | -| **F-5** | 从 uvprojx 中**移除未使用的 LVGL 控件源文件**(201 个 → 实际需要的子集) | 编译时长 −40% 左右 | 与 F-2 配合;`lv_conf` 关开关后文件仍参与编译,删文件才省编译时间 | ❌ 未办(uvprojx 现挂 **323 个 `.c`,其中 LVGL 仍 201 个**)。⚠ F-2 落地后这些 TU 现在编出来是**空目标文件**,删文件的收益更纯粹、风险更低 | -| **F-6** | 双精度软浮点:`dadd`/`dmul`/`ddiv`/`depilogue`/`dfixul`(`mf_w.l`),来自 `printf` 的 `%f`/double 提升 | −1 KB + 运行期性能 | 日志与 UI 全用定点;把 `%f` 改整数刻度 | ❌ 未办(新镜像仍链入 `dadd.o`) | +| **F-4** | 关闭未用的绘制子模块与 `LV_USE_SNAPSHOT`(MCU 端)/`LV_USE_OBJ_PROPERTY`/`LV_USE_FLOAT` 等 | 原估 ≈10 KB | **五项字节数逐字节核对仍准确**(3,246 + 2,960 + 1,972 + 952 + 930 = 10,060 B),**但没有一项有开关**:根因在 `Lib/lvgl/src/draw/sw/lv_draw_sw.c` 的 `execute_drawing()` 用**无条件 switch** 引用全部 task 类型(只有 VECTOR 带 `#if`)→ 链接器 `--remove` 无从下手。上游唯一总开关 `LV_DRAW_SW_COMPLEX`(关它可连带去掉 `mask` 3,862 与 shadow、arc、mask_rect、triangle、圆角/渐变/粗斜线分支,≈9.5–11 KB)**在本工程不可关闭**:主界面顶部"开口浅 V"两条 3 px 粗斜腿由 `Drivers/BSP/UI/ui_deco.c` 用 `lv_draw_line()` 绘制,斜段只在复杂渲染器下存在,**2026-09-03 已实测失败并把两端 =1 固化** → `../UI设计/UI_设计架构.md` §1.4 第 7 条、`../UI设计/UI_界面制作流程.md` 陷阱表。⚠ **原"mask / grad 是文字与矩形绘制必经路径"的理由同样错**:字形走 `lv_draw_sw_letter.c` 的 `blend_dsc.mask_buf`(blend 层的字形位图),不经 `lv_draw_sw_mask_*`;关不掉的真实理由是**斜线**、不是文字 | ❌ **判定不做**。剩余唯一路线 = 给 `Lib/lvgl` 打本地补丁给分发分支逐个加门控(阴影、弧、mask_rect、三角 + 图片链,理论上限 ≈16 KB),代价是第三方补丁登记 + 每次升级重放 + 逐分支像素回归;而 Flash 只占 22.1%(余 ≈800 KB)、产品需求无 OTA/双镜像预算 → 收益不抵代价 | +| **F-5** | 从 uvprojx 中**移除未使用的 LVGL 控件源文件**(201 个 → 实际需要的子集) | 原称编译时长 −40% | uvprojx 实测 **326 个 `.c`,其中 LVGL 201 个**;`.map` 里 LVGL 有产出 74 个、**零产出 127 个**(空 TU 样例:`lv_draw_3d`、`lv_draw_vector`、`lv_draw_arc`、`lv_obj_property`、`lv_draw_sw_blend_to_rgb565` 与 `_al88`、`_l8`)。但增量构建实测 **4~5 s**(`MDK-ARM/build_log.txt` 的 `Build Time Elapsed`),空 TU 只在全量重建或改 `lv_conf.h` 时才参与重编;**远程 CI 刻意不跑 `@build`**(需 Keil 授权)→ 对 CI 时长零收益。**"−40%"在仓库里没有任何基线记录**,不予复述 | 🟡 **降级为观察项**(非产品指标)。真要做:用 Keil 原生 `0`(保留清单、可逆、diff 小)而非删条目,且**必须排在任何 `lv_conf.h` 改动之后**(空 TU 集合随裁剪变化);动手前先补一次全量构建计时做基线 | +| **F-6** | 双精度软浮点:`dadd`/`dmul`/`ddiv`/`depilogue`/`dfixul`(`mf_w.l`),原称"来自 `printf` 的 `%f`/double 提升" | 原估 −1 KB + 运行期 | **原建议的成因判断不成立**:全库 **0 处 `%f`/`%g`/`%e`**(扫 `App/`、`Src/`、`Inc/`、`Drivers/BSP/` 共 173 个 `.c/.h`;`App/util/task_prof.c` 与 `App/task/adc_task.c` 的注释早已改用定点整数打印)→ "把 `%f` 改整数刻度"没有可执行对象。剩下的 `dadd`+`dmul`+`ddiv`+`depilogue`+`dfixul` = **1,018 B** 由 `mc_w.l(printfa.o)` 的 `_printf_core → _fp_digits` **无条件引用**(`.map` 交叉引用可查):只要还用 MicroLIB `snprintf` 就删不掉。自研真正的双精度只有 `App/algo/prot_set.h` 两个 Q10 宏里的显式 `(double)` | ✅ **已落地(2026-10-22)**:宏改单精度(去 `(double)`、`1024.0` → `1024.0f`)→ `@build` 0 错 0 警、Code 213,520 → **213,188(−332 B)**;`.map` 里 `dflti`、`d2f`、`f2d`、`dfixi`、`fepilogue` 共 300 B 消失,自研侧不再引用任何双精度 helper。**数值逐位等价**(×/÷1024 是 2^10 指数平移;宏内 42 个字面量 + `int32` 全域往返穷举零差异);`prot_set` 90/90、`prot_elm` 47/47、`iec104` 97/97 主机单测全过;真机 `@test` PASS(2026-10-22,无 `[ERR]`/Fault)。运行期收益:保护判据每 20 ms 每元件 3 次定值读取由软件双精度改为 F407 单精度 FPU | -**剩余可回收 ≈ 10–11 KB Flash**(F-4 可评估部分 + F-6);F-5 省的是编译时长不是 Flash。 +**Flash 侧剩余可回收项 = 0**:F-4 需给 `Lib/lvgl` 打本地补丁(已判定不做),F-6 已收口,F-5 省的是编译时长不是 Flash。 ### 5.5 内存治理长效机制 @@ -562,7 +562,7 @@ const ui_page_desc_t ui_page_deadzone = UI_FORM_PAGE("遥测死区", s_items_dea |------|------| | 页面**不得**新增静态大缓冲;文本缓冲统一用 `UI_BUF_STRLEN` | 现有 `s_ts/s_desc` 已是范式 | | 每页**只用** `lv_style_const_prop_t`,禁止运行期 `lv_style_init` | 已验证动态样式每次泄漏 88 B | -| 优先自绘(`lv_draw_*` + `lv_text_get_width`),新控件需评审(会破坏 §5.4 F-2 **已落地**的裁剪,且须两端同步) | LVGL 现占镜像 **37.8%**(87,706 / 232,280 B) | +| 优先自绘(`lv_draw_*` + `lv_text_get_width`),新控件需评审(会破坏 §5.4 F-2 **已落地**的裁剪,且须两端同步) | LVGL 现占镜像 **37.8%**(87,706 / 231,768 B,2026-10-22 构建) | | 帧缓冲任何改动必须遵守 R-4(副本数 ≤ 2) | 当前 4 副本 12.8 KB | | `LVGL 池`用量必须经 `lv_mem_monitor` / 池水位门禁实测后才允许扩大 | **16 KB**(R-9 于 2026-10-15 由 40 KB 降下;实测峰值 6,568 B = 池的 40%,余 ≈9.8 KB) | @@ -587,7 +587,7 @@ const ui_page_desc_t ui_page_deadzone = UI_FORM_PAGE("遥测死区", s_items_dea | 波次 | 本报告条目 | 验收要点 | |------|-----------|---------| | ~~**W3 预算与内存**~~ ⏸ | **整簇暂缓(用户裁定 2026-10-15)**:R-9 ✅ 已落地不回退;R-2 后半 / R-3 / R-4 / R-6 不再排期 | 暂缓期间**无验收动作**;`mem-budget` 92% 门禁与台账、趋势、`stack_report.py` / `ram_report.py` 观测**照常跑**(它们是判断何时重开的输入)→ 重开条件见 §5.3 | -| **W4 结构债** | N-14、F-4/F-5/F-6、S-1/S-2/S-4/S-5;`rs485_task.c` 随 B2 出注册白名单 | `--strict` 默认化;`bsp_err_t` 进规范 | +| **W4 结构债** | N-14、F-5(观察项)、S-1/S-2/S-4/S-5;`rs485_task.c` 随 B2 出注册白名单(~~F-4/F-6~~ 已于 2026-10-22 收口,见 §5.4) | `--strict` 默认化;`bsp_err_t` 进规范 | | **W5 验证常态** | P1-10 收尾(构建实测链接 + `@test` 闭环) | 逢窗口顺手做 | | **W6 UI 扩展** | U4 残余 → U1 → U2/U3 → U5(27 页) | 新增一页 ≤30 行;**2026-10-15 启动**(见 §6.5 注) | | **W7 仓库决策** | D-1(登记簿 N-29) | **已决策暂不处理**;推送/协作前重评 | @@ -664,6 +664,7 @@ const ui_page_desc_t ui_page_deadzone = UI_FORM_PAGE("遥测死区", s_items_dea | **2026-10-20** | **补上 U4 缺的第三件:golden 像素回归入提交门禁(35→36 钩子)** | 先实测成本再定形态:改一个 UI 源文件后「增量重编模拟器 + 两条 golden」合计 **2~4 秒**,支持走自动门禁(若实测要几分钟,正确做法是明确不挂、改为文档化人工门禁——一个逼人 `--no-verify` 的门禁等于没有门禁)。新增 `scripts/check_ui_golden.py` 包装器(**有意忽略 argv 并 `pass_filenames: false`**:两条 golden 按整棵菜单树 + 全量参考图工作,不接受文件参数),新钩子 `ui-golden` 的 `files:` 覆盖 UI 源 + `ui_task.{c,h}` + 模拟器 tests/sim/src + `lv_conf.h` + 包装器与本配置文件自身。 ⚠ **端到端验的是钩子不是脚本**:干净树连跑 3 次 `rc=0` 全 Passed;注入 `ui_page_dc.c` 的 `.top_y +5` → **钩子 Failed** 并点名 `[dc] FAIL 与参考页不一致(1882 px 差异)`;还原后 `git diff` 干净、`simulator/tests/ref` 的 `git status` 为空(**全程未用 `--update` 刷基线**)。诚实记录一次瑕疵:首次实测在连续注入/还原的紧邻重建之间偶发失败一次,疑似 MSBuild 节点争用,已把"单次失败先复跑、连续两次才当真、不许直接绕过"写进钩子注释。 据此 §6.5 U4 由 **2/3 → 3/3**(这次是"真进了自动门禁",不是"脚本存在")、§6.1 golden 行转 ✅、§0.1 UI 行缺口描述更新、`AGENTS.md` 钩子数与文末索引 35→36、`pre-commit使用说明.md` 概览计数同步。**W6 剩余**:U2 合并两页记录、U5 落地目标页(须先对齐"目标页 vs 现存 7 个 `ui_page_*.c`"差集)。 +| **2026-10-22** | **执行 §5.4:F-6 落地、F-4 判定不做、F-5 降级观察项**(登记簿 N-28 同步改写) | 动手前逐条对 `.map` 与源码核(本报告"建议栏不可照抄"总口径的又一次复现——三处误判全部出在**建议栏**,"发现"栏字节数全对)。**F-6 ✅**:`App/algo/prot_set.h` 两个 Q10 宏去掉显式 `(double)`、`1024.0`→`1024.0f` → `@build` 0 错 0 警、Code 213,520→**213,188(−332 B)**;`.map` 中 `dflti`、`d2f`、`f2d`、`dfixi`、`fepilogue` 共 300 B 消失,自研侧不再引用任何双精度 helper。**原报告"来自 `printf` 的 `%f`"是误判**:全库 0 处 `%f`,剩余 `dadd`+`dmul`+`ddiv`+`depilogue`+`dfixul` = 1,018 B 由 `mc_w.l(printfa.o)` 的 `_printf_core → _fp_digits` 无条件引用,MicroLIB 层面删不掉。**数值等价用穷举证明**(宏内 42 个字面量 + `int32` 全域 ÷1024 往返 4.49×10⁶ 例零差异;×1024 方向 2×10⁵ 例零差异);回归 = `prot_set` 90/90、`prot_elm` 47/47、`iec104` 97/97 主机单测全过。**F-4 ❌ 判定不做**:五项字节数逐字节仍准(合计 10,060 B)但**无一项有开关**,根因是 `lv_draw_sw.c` 的 `execute_drawing()` 无条件 switch 引用全部 task 类型;唯一总开关 `LV_DRAW_SW_COMPLEX` 被 `ui_deco.c` 的"浅 V"3 px 粗斜腿锁死(**2026-09-03 已实测失败并两端固化 =1**);**原"mask/grad 是文字必经路径"的理由同时证伪**(字形走 blend 层 `mask_buf`,不经 `lv_draw_sw_mask_*`)。**F-5 🟡 降级观察项**:uvprojx 实测 326 个 `.c` / LVGL 201 个 / `.map` 零产出 **127 个**,但增量构建实测 4~5 s、远程 CI 刻意不跑 `@build`,原"−40%"无基线记录。同步更正 §0.1 Flash 行、§0.4 Flash 行、注册表 uvprojx 行、§1 口径行、§5.1 快照注与要点行、§6.4 LVGL 占比分母、W4 波次行;台账受管区与内存快照已 `--write` 回填(`mem-budget` / `mem-numbers` 转绿)。**`@test` 台架 PASS**(固件戳 `fw build: Oct 22 2026 10:36:15 suite=NONE dstr=off`;无 `[ERR]`/`ERROR`/`FAIL`/Fault,708 ms 到 `net init: OK`,`protect task start`、`i104: listening on 2404`、`[STACK]` 三面水位齐;`adc`/`phasor`/`freq` 心跳持续) | | **2026-10-14** | **清理:删除已完成与过时内容** | ① **已修复项按销项删除**(去处见下表):N-02(FTP 鉴权)、N-03c(`Error_Handler` 降级)、**N-11(DMA 可达性三层防线 + 规则族 R1~R4)**、S-3(注册反向校验)、P2-5/P2-6(SD2506 负温度与 WRTC)、P2-8(`NET_RECV_TIMEOUT_MS` 已删)、P2-9(`mkdir` 幂等重试)、§5.5 前三条(内存治理三件套)、交付物清单已建项。② **删除过时层**:2026-09-16 / 2026-10-11 双列基线表与"复核期间未提交改动"口径说明、旧"组合结果预估"表、逐条"2026-10-11 复核"批注、历史变更记录行——内存数字改由 `../内存管理/RAM预算台账.md` 与 `scripts/ram_baseline.tsv` 持有。③ **按 2026-10-14 `.map` 与代码重测**全部保留结论的数字(含 `lftpd_log.c` 已删除并入 `lftpd_auth.c`,N-06 残余只剩 `rs485_task.c` 一条刻意缺口)。④ **修正三处错误**:R-5(`configMAX_PRIORITIES` 56→32)**判定不可行**(CMSIS-RTOS2 `#error`);原 §7 把报告 S-5(驱动统一错误码)与登记簿 S-5(卷锁覆盖面)混为一谈;原 §5.5 第 4 条建议的 `_Static_assert` 形态在 AC5 上取不到链接期地址,已被"窗口断言 + 启动自检 + 运行时守卫"三层取代。⑤ 报告自有编号**不回改、不重排**(`../编号规范.md`) | ### 已销项条目的记录去处 @@ -689,6 +690,7 @@ const ui_page_desc_t ui_page_deadzone = UI_FORM_PAGE("遥测死区", s_items_dea | U4 主体(golden 回归) | `simulator/tests/` 四脚本 + `../UI设计/UI_自动化测试流程.md`(残余 = 挂门禁,见 §6.3) | | R-1 / R-7 | `../子系统设计/看门狗设计说明.md` + AGENTS.md 任务表(`scripts/gen_task_table.py` 生成区) | | §5.5 前三条(92% 门禁 / 趋势基线 / 预算台账,登记簿 N-27 前半) | `../内存管理/RAM预算台账.md`(阈值与配额的**唯一权威**)+ `scripts/ram_baseline.py`(`--gate/--update/--trend/--write`)+ `../代码规范/pre-commit使用说明.md`(`mem-budget`) | +| **F-4 判定不做 / F-6 已落地(2026-10-22,登记簿 N-28)** | 实测复核与"为什么关不掉"记在本报告 §5.4;`LV_DRAW_SW_COMPLEX` 必须为 1 的约束本身在 `../UI设计/UI_设计架构.md` §1.4 第 7 条与 `../UI设计/UI_界面制作流程.md` 陷阱表;宏改动与等价性论证在 `App/algo/prot_set.h` 的 Q10 注释;MicroLIB `snprintf` 拖入 `_fp_digits` 的取证方法(在 `.map` 的 Section Cross References 区反查 `refers to mf_w.l(d*.o)`)见 §5.4 F-6 行 | | F-1 / F-2 / F-3(LVGL 死代码裁剪) | `../内存管理/RAM使用分析与优化方案.md` §2.6.4;`../UI设计/UI_设计架构.md` §1.4 第 10 条(**两份 `lv_conf.h` 必须同一特性子集**);`../UI设计/UI_自动化测试流程.md` 变更记录(池水位基线) | | **R-9(`LV_MEM_SIZE` 40→16 KB,登记簿 N-27 原 W3 的第一步,2026-10-15 已执行;该簇其余部分同日整簇暂缓)** | 取值依据与再降 8 KB 的前置写在 `Lib/lv_conf.h` 与 `simulator/lv_conf.h` 的池注释;实测水位 → `../内存管理/RAM使用分析与优化方案.md` §2.6.2 与 §阶段 1.1(已执行);解锁链第 ① 步 ✅(后续步骤暂缓)→ `../内存管理/RAM预算台账.md` §3;池容量口径 → `../UI设计/UI_设计架构.md` §1.2、`../UI设计/UI_界面制作流程.md` C4 | | **N-12 / N-13**(dhara 移植层 `is_free` 精度 + HAL 越界守卫,登记簿 **N-21**,2026-10-15 已销项) | `../架构设计/STM32F4-Base存储架构说明.md` §5.3(移植层两条硬约束:整页精确的原因链 + 错误码取舍与"为什么不会静默清卷")+ `Drivers/BSP/GD5F2GQ5UE/nand_ftl.c` 的 `ftl_page_in_range` / `ftl_block_in_range` / `dhara_nand_is_free` 注释 + 主机侧单测 `test/host/nand_port/`(含"旧算法只看页首 64 B"的对照用例,防止将来被改回去) | diff --git a/scripts/ram_baseline.tsv b/scripts/ram_baseline.tsv index 363f53df..f41da585 100644 --- a/scripts/ram_baseline.tsv +++ b/scripts/ram_baseline.tsv @@ -4,3 +4,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi 2026-10-14 212296 18740 1112 154456 231036 22.0 98144 74.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=40960;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;default_task.o=2736;sys_log_mcu.o=1924 2026-10-15 213540 18740 1136 131520 232280 22.2 75232 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736 2026-10-20 213356 18580 1184 131480 231936 22.1 75240 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736 +2026-10-22 213188 18580 1184 131504 231768 22.1 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736