build(mdk): Keil 可逆排除 126 个零产出 LVGL 编译单元,全量重建 21.5→18.3 s(-14.6%,#46) #87

Merged
wandering1 merged 1 commits from execute-issue-46-214251580469 into master 2026-11-06 01:04:34 +08:00
Collaborator

#46 的实测闭环:先补全量构建计时基线,再用 Keil 原生 <IncludeInBuild>0</IncludeInBuild> 可逆排除零产出 LVGL 编译单元。实测有收益(全量重建 -14.6%,影像逐字节等价),故按判据保留改动。

背景与判据

  • 登记簿 §6 第 4 项 / Issue #46:201 个 LVGL .c 中 127 个在 .map 零产出,但增量构建仅 4~5 秒,「有全量构建耗时痛点时先补计时基线,再用可逆排除;有实测收益才保留改动」。
  • 本 PR 即该判据的执行结果与证据。

方法

  • 环境:本机 C:\Keil_v5\UV4\UV4.exe(ARMCC 5.06 update 7),master c487ce42 全新克隆,全量重建用 UV4 -r(Rebuild all),计时为 UV4 进程级墙钟;每态 4 次。
  • 零产出认定:解析每次全量构建 .map 的 Image component sizes 表——Code/RO/RW/ZI 全为 0(含完全不在表中出现的空 TU)。3 次基线认定的零产出名单完全一致:127 个 = 121 空 TU + 6 仅调试记录。
  • 链接安全(关键约束):.map Cross Reference Table(10,355 行)做不动点收敛——「被排除对象定义的符号若被任何保留对象引用则必须保留」。唯一收敛损失:lv_circle_buf.c(保留的 lv_iter.o 静态引用它;armlink 先解析后死删,死删只影响最终影像、不豁免解析)。127 全排的尝试实测在链接期报 9×L6218E Undefined symbol lv_circle_buf_*(referred from lv_iter.o),已复现并据此定 126。

计时结果

态 编译单元数 全量重建墙钟 (s) 均值 (s) UV4 内部耗时
基线(master) 370 21.19 / 21.96 / 21.04 / 21.66 21.46 00:00:19
排除 126 后 244 18.13 / 18.54 / 18.45 / 18.20 18.33 00:00:16
  • 全量重建:均值 -3.13 s(-14.6%)。
  • 增量最坏对照(touch Lib/lvgl/lvgl.h 后 -b,最常见共享头改动场景):基线 9.66 s / 83 个编译单元,排除态 8.06 s / 45 个(-1.60 s / -16.6%;126 个被排除者中 38 个依赖该头)。

等价性证据(排除 ≠ 无副作用,这里给硬证据)

  • Program Size: Code=254820 RO-data=30896 RW-data=2072 ZI-data=150104——全部构建(基线×4、排除×4)四项全同。
  • .hex 解析为 286,084 个 flash 字节两两比对:地址集合全同;差异仅 2~4 字节、全部落在 0x08007C6B–0x08007C6F 的 "fw build: … HH:MM:SS" 身份戳时间窗内——基线构建之间同样只差这几字节,与排除无关。
  • .map 符号表(Image Symbol Table 段,6,419 行)逐行比对:排除构建是基线的真子集,基线独有 126 行恰为被排除编译单元的 ABSOLUTE 文件记录,其余符号名/取值/段/对象逐行相同;无任何符号地址移动。
  • 构建判定:0 Error(s), 0 Warning(s);registration-check 的 <FilePath> 集合不变(只加 <FileOption>,不删文件条目)。

改动形态与回滚

  • 单文件 MDK-ARM/STM32F407-Demo.uvprojx,+630/-0:126 个 LVGL <File> 各插入一个 <FileOption><CommonProperty><IncludeInBuild>0</IncludeInBuild></CommonProperty></FileOption>。文件保留在工程组内,UV4 GUI 里逐项勾选即可恢复;revert 单笔提交整体回退。
  • simulator/CMakeLists.txt 不涉及(模拟器编译面独立于 uvprojx);LVGL 库源码零改动。
  • 本机实测 UV4 构建对该工程文件零抖动(构建后 git status 除日志外无改动),故提交文件与构建所用文件字节一致;最终一次全量构建(18.20 s,0E0W)直接跑在提交文件的确切字节上。
  • 影像等价 + 本机 8 次全量构建零告警 ⇒ 不需要占用台架做烧写回归(镜像与被台架验收过的基线逐字节等价,除时间戳横幅)。

范围外观察(不在本 PR 动)

  • net_select.o、stream_buffer.o(非 LVGL)在 map 中同为 0 贡献,属 #46「继续观察」口径的后续候选。
  • lv_circle_buf.c 虽 0 产出但被静态引用锁死,普通手段不可排除(除非上游 LVGL 清理 lv_iter 的引用)。

验证清单

  • 全量重建基线 ×4 + 排除态 ×4:均 0 错误 0 警告
  • Program Size / .hex 字节级 / .map 符号表三重等价性
  • 增量对照(touch lvgl.h)基线态 9.66 s vs 排除态 8.06 s
  • 本地门禁(.venv 新克隆,ci_local.py):static 46/48 通过——含 ui-golden 像素回归(82 帧)、板端 UI 导航自检、生成器幂等、gitlint 10/10、coverage 等;size 门禁 rc=0
  • [!] static 唯二失败 mem-numbers/mem-budget 为先于本 PR 的工作区衍生漂移:用未打补丁的 master c487ce42 干净全量构建 .map 复跑同样失败(本 PR 影像逐字节等价,ER_IROM1=0x45C14/RW_IRAM1=0x17220/RW_CCM 四基线+排除态全同);新克隆无 .map 时 mem-numbers 按其设计直接 FAIL(提示先跑 /keil-build);台账受管区刷新属另行维护动作(check_mem_numbers.py --write / ram_baseline.py --write),不入本 PR
  • [!] 远端 Actions 现状:github.com 不可达导致 actions/checkout 在所有近期 run(含 master 自身,见 run 119–123)失败(dial tcp …:443 connectex),系先于本 PR 的基础设施故障;网络恢复后重跑即可
#46 的实测闭环:先补全量构建计时基线,再用 Keil 原生 `<IncludeInBuild>0</IncludeInBuild>` 可逆排除零产出 LVGL 编译单元。**实测有收益**(全量重建 -14.6%,影像逐字节等价),故按判据保留改动。 ## 背景与判据 - 登记簿 §6 第 4 项 / Issue #46:201 个 LVGL `.c` 中 127 个在 `.map` 零产出,但增量构建仅 4~5 秒,「有全量构建耗时痛点时先补计时基线,再用可逆排除;**有实测收益才保留改动**」。 - 本 PR 即该判据的执行结果与证据。 ## 方法 - 环境:本机 `C:\Keil_v5\UV4\UV4.exe`(ARMCC 5.06 update 7),master `c487ce42` 全新克隆,全量重建用 `UV4 -r`(Rebuild all),计时为 UV4 进程级墙钟;每态 4 次。 - 零产出认定:解析每次全量构建 `.map` 的 **Image component sizes** 表——`Code/RO/RW/ZI` 全为 0(含完全不在表中出现的空 TU)。3 次基线认定的零产出名单**完全一致**:127 个 = 121 空 TU + 6 仅调试记录。 - 链接安全(关键约束):`.map` **Cross Reference Table**(10,355 行)做不动点收敛——「被排除对象定义的符号若被任何保留对象引用则必须保留」。唯一收敛损失:`lv_circle_buf.c`(保留的 `lv_iter.o` 静态引用它;armlink **先解析后死删**,死删只影响最终影像、不豁免解析)。127 全排的尝试实测在链接期报 9×`L6218E Undefined symbol lv_circle_buf_*(referred from lv_iter.o)`,已复现并据此定 126。 ## 计时结果 | 态 | 编译单元数 | 全量重建墙钟 (s) | 均值 (s) | UV4 内部耗时 | |---|---|---|---|---| | 基线(master) | 370 | 21.19 / 21.96 / 21.04 / 21.66 | **21.46** | 00:00:19 | | 排除 126 后 | 244 | 18.13 / 18.54 / 18.45 / 18.20 | **18.33** | 00:00:16 | - 全量重建:均值 **-3.13 s(-14.6%)**。 - 增量最坏对照(`touch Lib/lvgl/lvgl.h` 后 `-b`,最常见共享头改动场景):基线 **9.66 s / 83 个编译单元**,排除态 **8.06 s / 45 个**(**-1.60 s / -16.6%**;126 个被排除者中 38 个依赖该头)。 ## 等价性证据(排除 ≠ 无副作用,这里给硬证据) - `Program Size: Code=254820 RO-data=30896 RW-data=2072 ZI-data=150104`——全部构建(基线×4、排除×4)**四项全同**。 - `.hex` 解析为 286,084 个 flash 字节两两比对:地址集合全同;差异仅 2~4 字节、全部落在 `0x08007C6B–0x08007C6F` 的 `"fw build: … HH:MM:SS"` 身份戳时间窗内——**基线构建之间同样只差这几字节**,与排除无关。 - `.map` 符号表(`Image Symbol Table` 段,6,419 行)逐行比对:排除构建是基线的真子集,**基线独有 126 行恰为被排除编译单元的 `ABSOLUTE` 文件记录**,其余符号名/取值/段/对象逐行相同;无任何符号地址移动。 - 构建判定:`0 Error(s), 0 Warning(s)`;`registration-check` 的 `<FilePath>` 集合不变(只加 `<FileOption>`,不删文件条目)。 ## 改动形态与回滚 - 单文件 `MDK-ARM/STM32F407-Demo.uvprojx`,+630/-0:126 个 LVGL `<File>` 各插入一个 `<FileOption><CommonProperty><IncludeInBuild>0</IncludeInBuild></CommonProperty></FileOption>`。文件保留在工程组内,UV4 GUI 里逐项勾选即可恢复;revert 单笔提交整体回退。 - `simulator/CMakeLists.txt` 不涉及(模拟器编译面独立于 uvprojx);LVGL 库源码零改动。 - 本机实测 UV4 构建对该工程文件**零抖动**(构建后 `git status` 除日志外无改动),故提交文件与构建所用文件字节一致;最终一次全量构建(18.20 s,0E0W)直接跑在提交文件的确切字节上。 - 影像等价 + 本机 8 次全量构建零告警 ⇒ 不需要占用台架做烧写回归(镜像与被台架验收过的基线逐字节等价,除时间戳横幅)。 ## 范围外观察(不在本 PR 动) - `net_select.o`、`stream_buffer.o`(非 LVGL)在 map 中同为 0 贡献,属 #46「继续观察」口径的后续候选。 - `lv_circle_buf.c` 虽 0 产出但被静态引用锁死,普通手段不可排除(除非上游 LVGL 清理 `lv_iter` 的引用)。 ## 验证清单 - [x] 全量重建基线 ×4 + 排除态 ×4:均 0 错误 0 警告 - [x] Program Size / .hex 字节级 / .map 符号表三重等价性 - [x] 增量对照(touch `lvgl.h`)基线态 9.66 s vs 排除态 8.06 s - [x] 本地门禁(`.venv` 新克隆,`ci_local.py`):static 46/48 通过——含 ui-golden 像素回归(82 帧)、板端 UI 导航自检、生成器幂等、gitlint 10/10、coverage 等;size 门禁 rc=0 - [!] static 唯二失败 `mem-numbers`/`mem-budget` 为**先于本 PR 的工作区衍生漂移**:用未打补丁的 master c487ce42 干净全量构建 .map 复跑同样失败(本 PR 影像逐字节等价,ER_IROM1=0x45C14/RW_IRAM1=0x17220/RW_CCM 四基线+排除态全同);新克隆无 .map 时 mem-numbers 按其设计直接 FAIL(提示先跑 /keil-build);台账受管区刷新属另行维护动作(`check_mem_numbers.py --write` / `ram_baseline.py --write`),不入本 PR - [!] 远端 Actions 现状:github.com 不可达导致 `actions/checkout` 在**所有**近期 run(含 master 自身,见 run 119–123)失败(`dial tcp …:443 connectex`),系先于本 PR 的基础设施故障;网络恢复后重跑即可
super_agent_bot added 1 commit 2026-11-06 00:16:55 +08:00
build(mdk): Keil 可逆排除 126 个零产出 LVGL 编译单元,全量重建 21.5→18.3 s(-14.6%,#46)
CI / 静态门禁 (pre-commit) (push) Failing after 44s
CI / 主机侧单测 (MSVC) (push) Failing after 44s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 45s
CI / 主机侧单测 (MSVC) (pull_request) Failing after 45s
488f6fbf21
按 #46 判据「有实测收益才保留改动」执行,证据(同机同基线 c487ce42,UV4 -r 墙钟):

- 基线 4 次全量重建均值 21.46 s → 排除态 4 次均值 18.33 s,-3.13 s(-14.6%);
  增量最坏对照(touch lvgl.h 后 -b)9.66 s/83 单元 → 8.06 s/45 单元(-16.6%)。
- 影像等价:Program Size 四项全同(Code=254820 RO=30896 RW=2072 ZI=150104);
  .hex 286,084 字节两两比对仅差 0x08007C6B–6F 的 fw 时间戳横幅(基线之间同差);
  .map 符号表逐行比对,基线独有 126 行恰为被排除单元的 ABSOLUTE 文件记录。
- 零产出认定:3 次基线 .map 的 Image component sizes 中 Code/RO/RW/ZI 全 0,
  名单一致(121 空 TU + 6 仅调试记录)。Cross Reference Table 不动点收敛得可安全
  排除集:lv_circle_buf.c 因被保留的 lv_iter.o 静态引用而保留(armlink 先解析
  后死删,127 全排实测 L6218E×9);净排除 126 个。
- 形态:仅加每文件 <FileOption><IncludeInBuild>0</IncludeInBuild>,不删条目,
  GUI 可逐项恢复,revert 单笔整体回滚;FilePath 集合不变(registration-check 过)。
- 本机构建对工程文件零抖动;最终一次全量构建(18.20 s,0E0W)跑在提交字节上。
- sim/CMake 不涉及;LVGL 源码零改动。台架回归不需要:镜像与已验收基线逐字节
  等价(除时间戳)。

Issue: http://100.123.83.113:3001/wandering1/STM32F4-Base/issues/46
wandering1 merged commit 829c2580bb into master 2026-11-06 01:04:34 +08:00
wandering1 deleted branch execute-issue-46-214251580469 2026-11-06 01:04:35 +08:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wandering1/STM32F4-Base#87