Files
STM32F4-Base/.dsh/skills/mem-budget/reference/shared-frame-attribution.md
T
wandering1 f08b12a46c docs(技能渐进展开): 五个技能正文逐字外置到 reference/,主文只留索引与指针
按「主文留头量、深规程外置」重写本仓技能,全部是逐字搬移:
搬移前断言原文每条非空行必须出现在新主文或 reference 文件里,
0 丢失才落盘;步骤编号一律不重排(正文有「第 12 步」交叉引用);
每个切点保留原小标题 + 索引(加粗引导句与步骤标题)+ 指针行。

主文变化(上限口径 = 插件写侧 65536 字节,见上一笔 skill-size 钩子):
- id-family-semantic-migration 33392 -> 10968(17%),reference 3 篇
- stale-doc-count-sweep 19811 -> 6945(11%),reference 2 篇
- mem-budget 19963 -> 13042(19%),reference 3 篇
- keil-build 12917 -> 8879(14%),reference 2 篇
- task-worktree 72601 -> 28139(42%),reference 8 篇

task-worktree 本笔同时收录另一会话已写完的 C2/D/G 三节正文——那
三处手改与我的拆分落在同一份文件改动里,不可分离;其内容同样已
随 reference/ 外置,主文只剩标题、索引与指针。

外置语料合计 122211 字节 / 30 篇:围栏数逐篇为偶,无 BOM/CR/U+FFFD。
draw-diagram 与 serial-boot-test 脚本是另一会话的在飞改动,本笔未含。

skill-size 钩子在本笔首次真跑(前一笔无 .dsh/skills 文件可触发)。

gate: pre-commit 全绿(doc-links、id-check-new、check-yaml、
      skill-size、check-added-large-files);30 篇 reference 手工字节
      体检 clean;skill() 逐个复载确认加载的是拆分版。
2026-10-29 15:03:12 +08:00

2.7 KiB

静态最坏链回归的归因(同涨同一数值 = 共享帧,不是调用方)(自 SKILL.md 外置)

本文由 mem-budget 的 SKILL.md「静态最坏链回归的归因(同涨同一数值 = 共享帧,不是调用方)」一节逐字外置而来(渐进展开:主文件只留索引与指针)。步骤号沿用原文,未重编。

  • 多条任务链分毫不差同涨/同降同一个数值(实测 default/net/iec104 三条 +80 B;断环后九条链各 −80 B) ⇒ 加深在这些任务共用的被调帧 / 共享尾段上,不在任何一个调用方。别逐个调用方翻, 也别先猜"新增了大局部缓冲"——实测猜错过一次(con_ring_try 只有 24 B 帧、没有数组)。
  • 逐棵树逐帧比 frame size,不要只比总数:
    • stack_report.py 输出的「Frame-size ranking (own frame)」表 + 每任务最坏链文本,锁定链尾公共段 (实测落在 dbg_console_write_line → con_append → dbg_console_drain,据此把账记到上一笔提交上);
    • 直接在 .htm 里找环:grep -ac 'In Cycle' MDK-ARM/STM32F407-Demo/STM32F407-Demo.htm(实测 17 处), 形态为 Max Depth = 280 + In Cycle 与 Call Chain = Error_Handler => dbg_console_write_line (Cycle)。 + In Cycle 表示 armlink 把环上所有帧计入含该环的每一条任务链——链接器幻影环能在无人改栈配置时让全仓链齐涨。
    • 实测样本(无人改栈配置、全仓链却齐涨的那种):taskEXIT_CRITICAL ⇒ vPortExitCritical ⇒ configASSERT ⇒ vApplicationAssertFailed ⇒ dbg_console_write_raw ⇒ 回到 console_log 内部 ⇒ 再进临界区; 它使 vApplicationAssertFailed 的 Max Depth 由 ~40 B 变 128 B + In Cycle,差 88 B ≈ 三条链同涨 80 B 的来源。 断环方向:内核临界区改 PRIMASK 保存/恢复(保存量放局部变量)→ 零调用帧、不成环; 断环的图证(该帧从「136 B + In Cycle」变成「8 B、不再 In Cycle」)比数字更有说服力。
  • Maximum Stack Usage = N bytes + Unknown(Cycles, Untraceable Function Pointers) 里的 + Unknown(...) 说明静态图对环与函数指针不可完全解析,静态数是估计值,别当精确值上报。
  • 不采信任何口头结论:用目标树的脚本 + .venv 解释器自己复算;复算同样先按上节钉身份。
  • 处置后的下一步:抬栈(Src/freertos.c 的 USER CODE 区,属 Ask-first 动作)或收紧共享缓冲 / 断环, 改前改后各一次 stack_report.py + ram_report.py,且"改后"那次必须落在一次新的 Linker run 上; 抬栈后跑 gen_task_table.py 同步任务表。