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:
2026-10-30 00:19:15 +08:00
parent 058e7c061c
commit 98d46e626d
3 changed files with 72 additions and 14 deletions
+61 -5
View File
@@ -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}%)")