4a4ad6bc5f
现状口径:/keil-build 与 /serial-boot-test 是 DSH 会话的技能调用名, 不是 shell 命令;「名 + 命令行参数」的命令形态改为可执行体 run_boot_test.py 的真实调用。 - AGENTS.md:别名说明重写为「技能调用名不是 shell 命令」,两条目改 「编译(/keil-build)」「串口回归(/serial-boot-test)」 - keil-build / serial-boot-test 两 skill 调用名与示例同步;task-worktree 方案文档去掉 @build/@test 惯例从句;@task 保留(不在点名范围) - 123 文件现状陈述全改;台架捕获、变更记录/时间线、rename 映射输入 等 41 行历史证据保留旧名 - gen_memory_svg.py 6 处措辞随改,3 张 SVG 产物同批重跑 - 顺手补并行方案同行漏网计数 51→52 钩子 验证:提交期快钩子对 123 文件实跑全 Passed;check_doc_links --all rc=0(3038 处、无法判定 0);check_mermaid --all rc=0;YAML 解析 52 钩子不变;skill-size rc=0;py_compile 全过;字节卫生零漂移。
6.6 KiB
6.6 KiB
mem-budget — RAM 总量红线(RW_IRAM1 / RW_CCM 超 92% 即拦)
一句话:它是总量刹车,不是预算规划器。它只管两件事:任一静态区域别超 92%,以及 台账里的水位数字别和
.map漂移。
- 配置:
entry: python scripts/ram_baseline.py --gate、pass_filenames: false、files:覆盖App/、Drivers/BSP/、Src/、Inc/、Lib/lv_conf.h等会影响占用面。 - 背景:登记簿条目「缩堆迁 CCM 后半(暂缓)」的前半;三件套里的机械部分(阈值门禁 + 趋势台账 + 台账受管区)。
1. 它在查什么
- 解析
.map,算RW_IRAM1、RW_CCM的占用率;任一 > 92.0% → FAIL,并附 Top-10RW+ZI对象表(直接告诉你是谁吃掉的); - 顺带核对
docs/内存管理/RAM预算台账.md的受管区(MEM_BUDGET:BEGIN/END)是否与.map一致——防台账漂移,与mem-numbers同一思路; .map不存在 → 自适应跳过(这台机器没做 Keil 构建)。
配套的两个入口(不在提交门禁里,属于日常):
--update:每次/keil-build后往scripts/ram_baseline.tsv追一行趋势;--trend:打印趋势并高亮RW+ZI较上一行增长 > 1 KB 的对象——把"ZI 增量超 1 KB 必须解释" 这条纪律机械化;--write:同步台账受管区(区域水位 + 子系统配额对照)。
子系统配额(规划值,改配额要先在台账变更记录里登记,再改脚本 QUOTAS):
网络 12 KB / 存储 12 KB / UI 16 KB / RTOS 堆 56 KB / 应用 8 KB。
2. 为什么要它
- 本仓 RAM 是真红线:
RW_CCM常年 87.9%(FreeRTOS 堆迁 CCM 之后),离 92% 只差几个百分点; 链接期才发现塞不下,代价是回退一大片改动。 - 实跑当前值:
RW_IRAM1 57.4%/RW_CCM 87.9%(阈值 92%)。 - 趋势台账让"谁什么时候吃掉了这 3 KB"可查,不必靠记忆。
3. 触发面 / 看不见什么
- 只看
RW_IRAM1与RW_CCM两个静态区域;不看:栈运行时水位、FreeRTOS 堆运行时余量、 堆碎片、MicroLIB 的 512 B C 堆(那条纪律是"自研代码禁用malloc/free",2026-10-23 起由coding-standard的 CODE-RULE-20 机器拦截(见coding-standard.md§1/§7),不再只靠评审)。 .map缺失即跳过 → 无构建的机器(含远端 CI)这一门不产生信息。
4. 报错怎么读
RAM 预算门禁 FAIL:RW_CCM 占用 92.3% > 92%(阈值 92%)
Top-10 RW+ZI 对象 …
-
单独跑:
& '.venv\Scripts\python.exe' scripts/ram_baseline.py --gate(只读);--trend -n 12看趋势。--gate不修改任何东西,要同步台账用--write。 -
报 FAIL 的正确动作是回去减(缩缓冲/挪区段/减日志调用点),不是抬阈值。
-
两类软提醒不拦提交:
tsv末行落后于.map(忘了跑--update)、.map早于最新源码(忘了/keil-build)。 -
退出码:0 = 通过或跳过 / 1 = 超阈值或台账漂移 / 2 = 解析失败(
.map读不出结构,不等于"没问题")。 -
.map解析口径复用scripts/ram_report.py,两个脚本不会各说各话。 -
为什么需要(背景):2026-09 体系评审提出的"超阈值即失败 + Top-10 附表"此前没有任何机械检查 ——
mem-numbers只核数字对不对,不判是否超限。
5. 好处
- 总量红线机械化,红线以下谁都能放心加东西;
- Top-10 归属表把"超了"变成"某某对象吃了多少",省掉一次手工 .map 考古;
- 趋势 + >1 KB 高亮让"增量必须有解释"变成可查记录,而不是口头承诺。
6. 限制与盲区
- 92% 是拍的管理阈值,不是安全余量计算(脚本里
THRESHOLD_PCT = 92.0)。它不回答 "还剩多少才够下一个任务/缓冲"——那是docs/内存管理/RAM预算台账.md的配额表与人的事。 - 静态视角:栈峰值、堆低水位、碎片一概看不见(运行时水位要靠串口
[STACK]与stack_report.py)。 - 只看两个区:Flash(
ER_IROM1)不在本门阈值内,它由mem-numbers报数、无人卡阈值。 .map缺失即"通过"式跳过 → 在没有 Keil 构建的环境里绿,不代表有余量。远端缺口已于 2026-10-25 关闭:scripts/check_size_gate.py --ci用同码凭证按同一常数复核红线(runner 无需 Keil),--gate无.map的 SKIP 文案也已改为明说「SKIP 不等于 PASS」;口径正文 = 该脚本 docstring。- 配额对照是"目标态 vs 现状",现状超配(例如 UI)会被如实展示但不拦提交——它是台账,不是红线。
- 阈值/配额改动没有双人复核机制,改
QUOTAS或THRESHOLD_PCT只靠提交说明约束。 - 并行分支约定(Lead 裁决 2026-10-12):分支不跑
--write,台账由主干统一回填;分支上 本门与mem-numbers可能因受管快照与.map漂移而红,那不代表预算超标(处置见 §7 的mem-numbers篇)。 - 同码凭证在「多人同树」下必然不成立(2026-10-27 实测):
check_size_gate.py --local的代码指纹取 git 索引里的 blob,所以「工作区有别人在飞、尚未入索引的改动」时指纹一定对不上,报「这份源码没有被 真实链接测量过」——这不是预算问题,也不拦提交(该脚本只挂在scripts/ci_local.py的体积门禁,不在 51 条 pre-commit 钩子内)。判据:报错里若同时列出「未入索引的文件」且那些文件正被别的任务改,就等它们入库后 统一/keil-build→ram_baseline.py --update补凭证,别为了把它调绿去git add别人在飞的改动。本条写作时 (2026-10-27 09:4x)凭证仍是红的:App/protocol/iec104/iec104_comm.{c,h}正被通讯道改、未入索引; 回填动作发生在该卡入库之后,届时以--update的实际输出为准,本节不预告结果。
7. 豁免与基线
- 没有基线、没有
--no-verify之外的合法豁免:超了就减。 docs/内存管理/RAM预算台账.md的受管区是事实展示区,不是豁免登记表;别在那里"解释一下"就算过关。
8. 改这个门禁本身
- 抬阈值前必须在台账里写清"为什么 92% 变松了",否则等于把刹车线往后画;
- 新增区域(例如再开一个自定义段)要同时改解析器与台账口径,否则新区域完全不在监控内;
--update的 tsv 是趋势事实源,改列格式会让--trend的历史对比失效。