Skip to content

Commit 3a6fe5a

Browse files
committed
docs(bench): edit-body owes a cascade only when the body is IN the BMI
用户问:接口没变的话,改函数体真的需要级联吗?分离实现的场景呢? 直接量了(GCC 16.1,比对改动前后的 BMI): | 改什么 | BMI | 级联 | |---|---|---| | `.cppm` 里一个自由导出函数的函数体 | **逐字节相同** | 不需要 | | `.cppm` 里**导出类的成员函数**(内联定义) | **不同** | **需要** | | 独立 `.cpp` 实现单元里的函数体 | **逐字节相同** | **不需要** | 类的成员函数体是类定义的一部分,而类定义是每个导入者都必须看到的,所以它进 BMI;自由函数的函数体不进,实现单元里的任何东西都不进。 所以「改一个函数,四十个模块重建」不是具名模块的固有代价,而是**函数体写在哪里** 的后果。mcpp 的 `src/version_req.cppm` 正好是第一种(扰动落在 `Version::str()`, 一个导出类的成员),所以它的 edit-body 是接近全量重建 —— 而这是对的。 原来的说法「接口单元里的内联函数体,BMI 合理地变了」对被测的那个 case 成立, 但把范围说宽了。xlings 那两个 pin 量的正是这件事:把实现移出接口单元后, 同一个工程的 edit-body 从 88.33s 降到 **1.77s**(~50×)。
1 parent 9909e71 commit 3a6fe5a

1 file changed

Lines changed: 28 additions & 2 deletions

File tree

bench/SPEC.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ job: the cell still runs, and its note says what to distrust.
215215
| `noop` | nothing | how cheap is "already up to date" |
216216
| `touch-hub` | mtime bump on a widely-imported unit, **content unchanged** | can the engine prove the interface did not change? |
217217
| `edit-comment` | a comment inserted into that same unit | the bytes *did* change but the interface did not — only an engine that compares the produced BMI avoids the cascade |
218-
| `edit-body` | a real semantic edit inside a function body | the everyday loop. For an inline body in an interface unit the BMI legitimately changes and a cascade is **correct** |
218+
| `edit-body` | a real semantic edit inside a function body | the everyday loop — and whether a cascade is owed depends on **where the body lives**, not on the edit. See below. |
219219
| `touch-leaf` | mtime bump on a unit nobody imports | recompile 1 + link |
220220

221221
`edit-comment` exists **separately from `edit-body`** on purpose: without the
@@ -247,7 +247,33 @@ reason: **a number whose meaning depends on an invisible choice is not a
247247
measurement.**
248248

249249
`edit-body` is the control that keeps the suite honest in the other direction —
250-
there, no engine should be fast, and one that is has skipped work it owed.
250+
where a cascade IS owed, no engine should be fast, and one that is has skipped
251+
work it owed.
252+
253+
#### But a body edit does not always owe a cascade, and that is the point
254+
255+
Measured directly, GCC 16.1, comparing the BMI before and after:
256+
257+
| what is edited | BMI | cascade |
258+
|---|---|---|
259+
| a free exported function's body, in the `.cppm` | **byte-identical** | not owed |
260+
| a **member function of an exported class**, inline in the `.cppm` | **differs** | **owed** |
261+
| a body in a separate `.cpp` implementation unit | **byte-identical** | **not owed** |
262+
263+
A class's member function bodies are part of the class definition, which every
264+
importer has to see, so they are serialised into the BMI. A free function's body
265+
is not, and nothing in an implementation unit is.
266+
267+
So "editing one function rebuilt forty modules" is not inherent to named modules
268+
— it is a consequence of where the body was written. `mcpp`'s own
269+
`src/version_req.cppm` is the first case (the perturbation lands in
270+
`Version::str()`, a member of an exported class), which is why its `edit-body`
271+
row is a near-full rebuild and why that is correct.
272+
273+
**This is what the two xlings pins measure.** Moving the implementations out of
274+
the interface units takes `edit-body` from 88.33s to **1.77s** on the same
275+
project — ~50x, the largest single effect anywhere in this suite, and a code
276+
style rather than an engine feature.
251277

252278
Real projects run five of the six: `touch-leaf` needs a unit nobody imports
253279
*and* a stable name for it, which a generated fixture has by construction and a

0 commit comments

Comments
 (0)