fix(内存台账): subsystem_of 补齐 12 个 App 对象前缀并加未归类兜底
按台账 §2「应用 = App/ 其余」自家口径重算归集。此前 wave_、iec104*、 soe_、meas、freq、run_par、protect_task、task_prof、boot_stats、 vol_idle_sync 都不在前缀表里,12 个对象 9,445 B 静默落进「其它」(参考 行、无配额),配额 8 KB 的「应用」行看不见录波与 SOE 支路。补齐后 应用 16,888 → 26,333 B、其它 15,849 → 6,404 B;区域水位与 92% 红线不变 (台账受管区已 --write 回填)。 兜底:App 下的 .c 编出的对象只要落进「其它」,--gate 就逐条 WARN 点名 (软提醒不拦)—— 下一个新增 App 目录不会再静默隐身。台账 §2 口径表、 应用条目、变更记录与 内存内容分配策略 §6 那条「本卡不动,已报 lead」 同步改口。
This commit is contained in:
+10
-8
@@ -26,8 +26,8 @@
|
||||
| 存储 | 7,072 B | 12 KB | OK |
|
||||
| UI | 36,428 B | 16 KB | ⚠ 超 19.6 KB |
|
||||
| RTOS 堆 | 57,376 B | 56 KB | 堆=配额 |
|
||||
| 应用 | 16,888 B | 8 KB | ⚠ 超 8.5 KB |
|
||||
| 其它 | 15,849 B | — | 参考 |
|
||||
| 应用 | 26,333 B | 8 KB | ⚠ 超 17.7 KB |
|
||||
| 其它 | 6,404 B | — | 参考 |
|
||||
<!-- MEM_BUDGET:END -->
|
||||
|
||||
- **门禁**:pre-commit `mem-budget` 钩子(`scripts/ram_baseline.py --gate`)——
|
||||
@@ -51,8 +51,8 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
| 存储 | `gd5f*` `nand_*` `ff*` `diskio*` `vol_lock*` + dhara 裸名(`map/journal/nand/fctl/era.o`) | `cfg_*`(算应用) |
|
||||
| UI | `lv_*` `ui_*`(含 `ui_net_sink`、`ui_task`) | — |
|
||||
| RTOS 堆 | `heap_4.o`(CCM)——配额 = `configTOTAL_HEAP_SIZE` 本身 | 内核对象(`tasks/queue/timers/...` 归"其它") |
|
||||
| 应用 | `App/` 其余:采集 `adc_*`、保护 `prot_*`、相量 `phasor/sample_ring`、配置 `cfg_*`、日志 `sys_/dbg_/console_log`、对时 `time_sync*`、`sys_clock`、`task_watchdog`、`sha256`、`tpafe*`、`sd2506`、`default_task` 等 | — |
|
||||
| 其它 | 内核对象、HAL、CMSIS、启动文件、C 库、链接器填充 | — |
|
||||
| 应用 | `App/` 其余——**前缀清单以 `scripts/ram_baseline.py` 的 `subsystem_of()` 为准**:`adc_*` `tpafe*` `sd2506` `prot_*` `protect_task` `phasor` `sample_ring` `wave_*` `meas` `freq` `run_par` `iec104*` `soe_*` `cfg_*` `sys_*` `dbg_*` `console_log` `time_sync*` `sys_clock` `task_watchdog` `sha256` `default_task` `test_task` `task_prof` `boot_stats` `vol_idle_sync` | `App/task/ui_task*`(首匹配算 UI) |
|
||||
| 其它 | 内核对象、HAL、CMSIS、启动文件、C 库、链接器填充——**不含 `App/` 任何对象**:漏登记会被 `--gate` 的兜底 WARN 逐条点名(2026-10-29 加) | — |
|
||||
|
||||
**现状判读(2026-10-12 建档)**:
|
||||
|
||||
@@ -62,11 +62,12 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
**这条 ⚠ 会长期挂着**,判读时按已知挂账处理,别每轮当新问题追;重开条件 → `RAM使用分析与优化方案.md` §4。
|
||||
- **RTOS 堆 = 配额本身**:56 KB 即 `configTOTAL_HEAP_SIZE`(2026-10-12 B5 由 48 KB 扩容,见 §6;
|
||||
`heap_4.o` 另含 32 B 元数据,不计超);**改堆 = 改配额**,必须先过本文件 §6 登记。
|
||||
- **应用 ⚠ 小幅超**:8 KB 为报告规划值;2026-10-10 栈整改把 3 处 `FIL` 从栈搬进 BSS
|
||||
- **应用 ⚠ 超配额**(现值见 §1 受管区):8 KB 为报告规划值;2026-10-10 栈整改把 3 处 `FIL` 从栈搬进 BSS
|
||||
(静态 +4,128 B,见 `docs/内存管理/RAM使用分析与优化方案.md` §4"2026-10-10 复测")——
|
||||
属已评审的"以空间换栈安全",差额在此如实体现。2026-10-29 故障录波落盘道又把 `default_task.o`
|
||||
推高 1,204 B(该行现值 16,888 B);**录波环本体 5,300 B 不计入本行**——`subsystem_of()`
|
||||
没有 `wave_` 前缀,它落在「其它」,要读全貌看 `docs/内存管理/内存内容分配策略.md` §6 的 per-file 台账。
|
||||
属已评审的"以空间换栈安全";2026-10-29 故障录波落盘道又把 `default_task.o` 推高 1,204 B。
|
||||
**同日修正归集口径**:`subsystem_of()` 此前没有 `wave_` `iec104*` `soe_` `meas` `freq` `run_par`
|
||||
等前缀,12 个 `App/` 对象 9,445 B 被静默算进「其它」(当时「应用」行只有 16,888 B,看着离配额不远);
|
||||
补齐后本行才真含录波环 `wave_ring.o`(约 5.3 KB)。per-file 全貌 → `docs/内存管理/内存内容分配策略.md` §6。
|
||||
|
||||
## 3. CCM 分配台账(谁能用 CCM)
|
||||
|
||||
@@ -99,3 +100,4 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
| 2026-10-12 | **RTOS 堆配额 48 KB → 56 KB**(`QUOTAS` 同步) | B5 protectTask 立项:iec104Task(2.5KB)+protectTask(2KB)+TCB 入堆后 48KB 池 min_ever 预估跌破 3,072 B 告警线 → `.ioc` 语义取数与有效性参数 `configTOTAL_HEAP_SIZE` 49152→57344(CCM 水位 75.3%→87.9%,仍 <92% 门禁;CCM 空闲降至 ≈8 KB)。连带影响见 §3 迁 CCM 后半链注记 |
|
||||
| 2026-10-12 | **任务栈 +1536 B(堆内用量,配额 56 KB 不变)**:defaultTask 1024→1280 words(+1024 B)、timeSyncTask 512→640 words(+512 B);产品任务栈合计 37,632→39,168 B | 登记簿 N-33 栈收口:B7 定值持久化把 defaultTask 静态链推到 3016 B(余 1080 < 30% 线)、timeSyncTask 链 1264 B(余 784 < ISR 底线 1024);B6 台架背书 min_ever=10000 → 抬后实测 `heap free=16400 / min_ever=8464`(与预算 −1536 完全吻合,>3072 告警线);`stack_report` 9 任务 0 FAIL + `@test` PASS,见 `RAM使用分析与优化方案.md` §1.4 |
|
||||
| 2026-10-29 | **故障录波数据面入册**:新增对象 `wave_ring.o` 5,300 B(ZI 5,256 + RW 44,落 SRAM1、CCM 增量 0);`default_task.o` 静态 2,736 → 3,940 B(+1,204 B,落盘道 `FIL` 528 + 分片缓冲 256 + 段头副本 136 + 段路径 17 + 打包上下文与 `DIR`/`FILINFO`);`RW_IRAM1` 81,536 → 89,936 B(62.2 % → 68.6 %,仍远低于 92 % 门禁);`RW_CCM` 三档恒 57,376 B | 决定人 lead。实测数字出自 lead 的权威构建(本工作树 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`,0 错误 0 警告,`scripts/ram_baseline.py --update` 同批入 tsv);预估约 5.9 KB vs 实测数据面 +6,760 B 的差额构成与三档对照见 `docs/内存管理/内存内容分配策略.md` §6;**未抬栈**(`scripts/stack_report.py` 九任务全 PASS),判据出处 `docs/子系统设计/故障录波设计说明.md` §7 |
|
||||
| 2026-10-29 | **归集口径修正(非配额改动)**:`subsystem_of()` 补 `wave_` `iec104*` `soe_*` `meas` `freq` `run_par` `protect_task` `task_prof` `boot_stats` `vol_idle_sync` 等前缀——12 个 `App/` 对象 9,445 B 此前静默落「其它」;「应用」16,888 → 26,333 B、「其它」15,849 → 6,404 B,区域水位与 92% 红线均未变。同脚本加兜底:`App/**/*.c` 的对象落进「其它」时 `--gate` 逐条 WARN(不拦) | 配额表看不见录波/SOE 支路;口径依据本文件 §2「应用 = `App/` 其余」 |
|
||||
|
||||
@@ -138,7 +138,7 @@ LVGL 集合明细(均在 SRAM):LVGL 池 16,384B(`lv_mem_core_builtin.o`
|
||||
- **栈:9 任务全 PASS、未抬栈**(`scripts/stack_report.py` 静态最坏链)——adcTask 1,424 B(余 1,136 B / 44 %)、defaultTask 3,040 B 不变、protectTask 880 B、uiTask 1,336 B(余 15,048 B / 91 %)。R6 三处同步里 `AGENTS.md` 栈表这一处的结论是**核对过、数值未变**。
|
||||
- **为什么比上一版低**:本表 2026-10-12 版记 95,816 B / 73.1 %,高于今天的 89,936 B。原因是此后 LVGL 内部池由 40 KB 缩到 16 KB(`docs/内存管理/RAM预算台账.md` §3「缩池 ✅ 2026-10-15」行;`scripts/ram_baseline.tsv` 2026-10-12 与 2026-10-24 两行的 `top_rwzi` 列可见 `lv_mem_core_builtin.o` 40960 → 16384)——**不是本波回收了什么**。
|
||||
|
||||
- **子系统归集的坑(本卡实测,值得记一笔)**:`scripts/ram_baseline.py` 的 `subsystem_of()` 按对象名前缀首匹配,**表里没有 `wave_` 前缀** → 录波环 `wave_ring.o` 5,300 B 落进 **「其它」(15,853 B,参考值、无配额)**,配额 8 KB 的「应用」行看不见它;落盘道 `default_task.o`(+1,204 B)与 `adc_task.o` 才计入「应用」(现值 16,888 B,本波前该行已在配额外,成因见 `docs/内存管理/RAM预算台账.md` §2「应用 ⚠ 小幅超」条)。结论:**别拿子系统表当录波预算的判据**,要按本节 per-file 台账读。要让配额表真看见录波支路,得给 `subsystem_of()` 加 `wave_` 前缀——那是脚本改动,本卡不动,已报 lead。
|
||||
- **子系统归集的坑(本卡实测 → 2026-10-29 已修)**:`scripts/ram_baseline.py` 的 `subsystem_of()` 按对象名前缀首匹配,当时表里没有 `wave_` 前缀 → 录波环 `wave_ring.o` 5,300 B 落进 **「其它」(当时 15,853 B,参考值、无配额)**,配额 8 KB 的「应用」行看不见它;落盘道 `default_task.o`(+1,204 B)与 `adc_task.o` 才计入「应用」(当时现值 16,888 B,本波前该行已在配额外,成因见 `docs/内存管理/RAM预算台账.md` §2 的应用条目)。**同日后续**:补齐 12 个 `App/` 对象(9,445 B)的前缀,并加兜底——`App/**/*.c` 编出的对象只要落进「其它」,`python scripts/ram_baseline.py --gate` 就逐条 WARN 点名(软提醒不拦)。结论仍然有效:**子系统配额行不是录波预算的判据**,要按本节 per-file 台账读;差别只在「应用」行现在真含录波支路,两个口径不再互相看不见。
|
||||
## 7. 布局变更验证阶梯(强制执行)
|
||||
|
||||
任何 scatter / CCM / 堆大小变更后,依次通过以下全部关卡方可认定生效:
|
||||
|
||||
+61
-5
@@ -78,7 +78,11 @@ def subsystem_of(obj):
|
||||
return RTOS_HEAP
|
||||
if n in _KERNEL:
|
||||
return "其它"
|
||||
if n.startswith(("app_", "adc_", "prot_", "phasor", "sample_ring",
|
||||
# 应用 = App/ 其余(台账 §2 口径)。新增 App 目录/前缀必须同步这里,
|
||||
# 漏登记不会报错,只会被静默算进「其它」——unattributed_app_objects() 是兜底信号。
|
||||
if n.startswith(("app_", "adc_", "prot_", "protect_task", "phasor", "sample_ring",
|
||||
"wave_", "meas", "freq", "run_par", "iec104", "soe_",
|
||||
"task_prof", "boot_stats", "vol_idle_sync",
|
||||
"sys_", "cfg_", "dbg_", "console_log", "task_watchdog",
|
||||
"sha256", "tpafe", "sd2506", "test_task", "time_sync",
|
||||
"default_task")):
|
||||
@@ -86,6 +90,56 @@ def subsystem_of(obj):
|
||||
return "其它"
|
||||
|
||||
|
||||
# 兜底:源文件在 App/ 却落进「其它」= 前缀表漏登记。2026-10-29 实测这样隐身了
|
||||
# 12 个对象 / 9,445 B(wave_ring 5,296 起),配额表完全看不见录波与 SOE 支路。
|
||||
_APP_SRC_DIR = REPO_ROOT / "App"
|
||||
_APP_STEMS = None
|
||||
|
||||
|
||||
def _app_stems():
|
||||
"""App/**/*.c 主干名集合(扫一次缓存);目录读不到就返回空集 = 兜底自动失效。"""
|
||||
global _APP_STEMS
|
||||
if _APP_STEMS is None:
|
||||
try:
|
||||
_APP_STEMS = {p.stem.lower() for p in _APP_SRC_DIR.rglob("*.c")}
|
||||
except OSError:
|
||||
_APP_STEMS = set()
|
||||
return _APP_STEMS
|
||||
|
||||
|
||||
def _obj_base(obj):
|
||||
return obj.rsplit("\\", 1)[-1].rsplit("/", 1)[-1].lower()
|
||||
|
||||
|
||||
def unattributed_app_objects(objs):
|
||||
"""[(对象, B)]:归进「其它」但源文件在 App/ 的对象,按字节降序。"""
|
||||
stems = _app_stems()
|
||||
if not stems:
|
||||
return []
|
||||
out = []
|
||||
for obj, nbytes in objs:
|
||||
if subsystem_of(obj) != "其它":
|
||||
continue
|
||||
base = _obj_base(obj)
|
||||
if base.endswith(".o") and base[:-2] in stems:
|
||||
out.append((obj, nbytes))
|
||||
return sorted(out, key=lambda t: (-t[1], t[0]))
|
||||
|
||||
|
||||
def warn_unattributed(info):
|
||||
"""打印未归类告警(软提醒,不拦);返回条数。门禁与 --write 都调,别让人静默隐身。"""
|
||||
missing = unattributed_app_objects(info["objs"])
|
||||
if not missing:
|
||||
return 0
|
||||
total = sum(n for _, n in missing)
|
||||
print("[WARN] %d 个 App/ 对象未登记进 subsystem_of() 前缀表,被算进「其它」而不是"
|
||||
"「应用」(台账 §2:应用 = App/ 其余),合计 %d B:" % (len(missing), total))
|
||||
for obj, nbytes in missing:
|
||||
print(" %-28s %6d B" % (_obj_base(obj), nbytes))
|
||||
print(" 修法:补 subsystem_of() 前缀 -> 重跑 @build -> --update / --write 回填台账")
|
||||
return len(missing)
|
||||
|
||||
|
||||
def collect(map_path):
|
||||
"""解析 .map → {'regions': {name: r}, 'subsys': {name: bytes}, 'top': [(obj, B)]}。"""
|
||||
data = ram_report.parse_map(str(map_path))
|
||||
@@ -96,11 +150,11 @@ def collect(map_path):
|
||||
subsys = {s: 0 for s in SUBSYSTEMS}
|
||||
for c in comps:
|
||||
subsys[subsystem_of(c["object"])] += c["rw_data"] + c["zi_data"]
|
||||
top = sorted(((c["object"], c["rw_data"] + c["zi_data"]) for c in comps),
|
||||
key=lambda t: (-t[1], t[0]))
|
||||
top = [t for t in top if t[1] > 0][:TOP_N]
|
||||
objs = [(c["object"], c["rw_data"] + c["zi_data"]) for c in comps]
|
||||
objs = [t for t in objs if t[1] > 0]
|
||||
top = sorted(objs, key=lambda t: (-t[1], t[0]))[:TOP_N]
|
||||
return {"regions": regions, "region_list": data["regions"],
|
||||
"subsys": subsys, "top": top}
|
||||
"subsys": subsys, "top": top, "objs": objs}
|
||||
|
||||
|
||||
def region_pct(r):
|
||||
@@ -238,6 +292,8 @@ def cmd_gate(args):
|
||||
if newest and newest > map_path.stat().st_mtime:
|
||||
print("[WARN] .map 早于最新源码——数字来自旧构建,建议先 @build 再提交")
|
||||
|
||||
warn_unattributed(info)
|
||||
|
||||
ir, cc = info["regions"].get("RW_IRAM1"), info["regions"].get("RW_CCM")
|
||||
print(f"RAM 预算门禁 PASS:RW_IRAM1 {region_pct(ir):.1f}% / RW_CCM {region_pct(cc):.1f}%"
|
||||
f"(阈值 {THRESHOLD_PCT:.0f}%)")
|
||||
|
||||
Reference in New Issue
Block a user