Validated metric: every individual call survives repetition, and the killer is inside draw()

Each variant is for(;;) { long spin; one call; } so a live app is in the overlay most of the time: control 27.2%, display_clear 26.9%, get_key 27.1%, delay_ms(40) 26.8%, print_tiny 27.0% -- all four calls survive repetition, and the control shows the metric separates the two cases.

That also means the previous round's variant B (four calls in a loop, no spin) was most likely not dead at all: it spends nearly all its time inside firmware functions, which look exactly like a dead app from the trace. The bisect has since closed on one function: Minesweeper with draw() gutted to display_clear() + blit_full() runs (97 samples inside the app, alternating with firmware PCs), while the full draw() draws nothing in twenty seconds and ink never leaves 210, so display_clear() never ran. The end of the app is inside draw()'s body.
This commit is contained in:
mckero committed 2026-10-02 10:44:18 +08:00
1 parent 057e408016
commit 5b861f82ab
2 files changed
+39

No files matched your search

+22
View File
@@ -864,6 +864,28 @@ comparable results, they are one good measurement and two unreadable ones. The f
self-contained spin with each call, so a live app is provably in the overlay most of the time and the trace
separates the two cases.
**Round 15: with a validated metric, every individual call survives repetition -- and the killer is inside draw().**
The metric first, because the previous round's was not trustworthy: each variant is for(;;) { long spin; one call; },
so a live app is in the overlay most of the time and a dead one is never there. The control (spin only) scores
27.2%; display_clear 26.9%, get_key 27.1%, delay_ms(40) 26.8%, print_tiny 27.0% -- **so all four calls survive
being repeated**, and the control proves the metric can tell the two cases apart.
That also means variant B of the previous round (four calls in a loop, no spin) was almost certainly not dead: it
spends nearly all its time inside firmware functions, which look exactly like a dead app from the trace. The
lesson is the same one this file keeps repeating -- a measurement that cannot show the thing you are looking for
will happily return zero.
With that out of the way, the bisect has closed on one function. Minesweeper with its whole draw() gutted to
display_clear() + blit_full() **runs** -- 97 samples inside the app, alternating with firmware PCs, and the
firmware still serving it. The full draw() draws nothing at all: over twenty seconds the panel never leaves the
launcher's title box, and ink stays at 210, meaning display_clear() never even ran. So whatever ends the app is
inside draw()'s body -- the eleven print_tiny calls, the framebuffer writes and the cursor invert -- and that is
the last mile.
Next: the same variant harness on the three pieces of draw() separately (the header text, the 81-cell loop, the
cursor), each with the loop spin that the surviving apps have.
That is where the next round starts: the same alternating-spin shape, one call at a time.
trace. That is a much better place to be than the emulator mystery this started as.
+17
View File
@@ -707,6 +707,23 @@ bug 是同一族:**传输还在进行时就告诉加载器「已完成」**,
get_key() 和只含 delay_ms() 的循环得了 0 分 —— 这三个结果**不可比**:一个是有效测量,另两个读不出结论。修法是让
每个调用之间夹一段**自包含的长自旋**,这样活着的应用在大多数时间**确定**在叠加区里,trace 就能把两种情况分开。
**第 15 轮:用经过验证的判据,四个调用各自被重复都没问题 —— 而凶手就在 draw() 里面。**
先说判据,因为上一轮那个不可信:每个变体都是 for(;;) { 长自旋 ; 一个调用 },这样活着的应用大部分时间在叠加区里,
而死掉的从不出现。对照组(只有自旋)27.2%;display_clear 26.9%、get_key 27.1%、delay_ms(40) 26.8%、
print_tiny 27.0% —— **所以这四个调用被重复都没有问题**,而对照组证明这个判据能区分两种情况。
这也意味着上一轮的变体 B(四个调用放进循环、中间没有自旋)**几乎肯定没死**:它把时间几乎全花在固件函数里,
而那从 trace 上看与死掉的应用一模一样。教训与本文件反复讲的那条相同 —— **一个看不见你所找之物的测量,会心安理得
地返回零。**
把这些排除之后,二分已经收拢到一个函数上。把扫雷整个 draw() 掏空成 display_clear() + blit_full() 之后它**能跑** ——
应用内 97 个样本,与固件 PC 交替出现,固件仍在为它服务。而完整的 draw() 什么都不画:二十秒里面板始终停在启动器
的标题框,ink 一直是 210,说明**连 display_clear() 都没执行过**。所以结束应用的东西在 draw() 的躯干里 —— 那十一次
print_tiny、帧缓冲写入与光标反相 —— 这就是最后一公里。
下一步:用同一套变体装置分别测 draw() 的三块(标题文字、81 格循环、光标),每块都带上那些能活的应用所拥有的循环自旋。
下一轮就从这里开始:同样的「自旋 + 单调用」形状,一次只放一个调用。
进去、读同一份 trace。比起一开始那个模拟器悬案,这是好得多的处境。