docs(N34): E2/E3/E4 实验结果与定案 + bench 实验区复活

E2:状态回读 18.1us(N=1000x2 逐值一致);LISTEN 可见延迟 100%
<=10ms 无长尾(24 轮)-> "每 poll 全量刷新"成立、reconciler 去抖
可减为 1。
E3:GET_CMD_STATUS 对 OPEN/LISTEN/CLOSE 无判别力(残留假阳性),
定案 cmd_done 用状态回读判据;SET 类命令态永不更新。
E4:排渣序列定案=读空 RX -> CLOSE -> 排空事件(quiescent) ->
轮询 byte0=00H;C 变体(不排渣)0/20 且级联自持,Trap 23 残渣
恰等于单 Socket RX 缓冲整容(rxdrain=2048,19/20)。
E2 补充发现(Phase 15 板测):LISTEN 态 CLOSE_SOCKET 二段关闭
(一次只拆监听 byte0 恒 05,再发一次才落 00)——Trap 09 open
重试环的芯片级原因。

bench:ch395f_reuse_bench.c 复活 N30_CHIP_BENCH 门控实验区
(旧 N-30 矩阵 s_bench_legacy=0 停泊),ch395f_reuse_host.py
增 --mode e4。注册(uvprojx/main.c)实验完已还原不入库。
This commit is contained in:
2026-10-13 12:43:56 +08:00
parent f7f17931c9
commit 83a70721bd
3 changed files with 653 additions and 10 deletions
@@ -562,3 +562,129 @@ PASV 重监听被垂死僵尸 accept 的竞态——且可由网卡抖动**确
**工具与留痕**:`test/host/pasv_probe.py`(新增);pktmon 抓包留存
`%TEMP%\n30_cap.etl`(3.9MB,含网卡抖动窗口,设备 IP 过滤)。
### E2 结果(2026-10-13 11:43–11:50,bench 实验固件 Code=213412,跑两遍,台架锁 N34)
**固件**:复活 `test/board/ch395f_reuse_bench.c`(N30_CHIP_BENCH 门控,内核前裸机;
旧 N-30 定案矩阵由 `s_bench_legacy=0` 停泊保留);注册 uvprojx Test 组 + `Src/main.c`
USER CODE 2 区(注册不入库,实验完 `git restore`)。DWT CYCCNT @168MHz(1 cycle≈5.95ns)。
两遍独立运行,本节数字两遍一致(第二遍为第一遍 C 变体级联污染后的干净重跑,E2/E3 复验)。
**单次回读成本**(`ch395f_get_socket_status`,N=1000×2 遍,两遍逐值相同):
| 统计 | cycles | µs |
|---|---|---|
| min | 3048 | 18.1 |
| avg | 3057 | 18.1 |
| max | 3481 | 20.7 |
**LISTEN 可见性矩阵**(裸 TCP_LISTEN 不轮询命令态,发命令后 +0/10/50/100ms 回读;
100ms 仍不可见则 10ms 节奏续查到 1000ms;12 轮×2 遍=24,轮间换端口):
| 首次观察到 TCP=01H | 计数 |
|---|---|
| +0ms | 14 |
| +10ms | 10 |
| >10ms | **0** |
**判据结论**:
1. 单次回读 18.1µs ≪ 100µs → **"每 poll 全量刷新"成立**(4 监听 × ~18µs ≈ 72µs ≪
1ms 轮询周期;`docs/网络/N34-自愈审计/实施方案.md` §4 第 1 项预估 ~15µs 量级坐实)。
2. LISTEN 可见延迟有界:100% 在 +10ms 内可见、无长尾 → **reconciler 去抖可减为 1 次**
(决策点后 ≥10ms 单次回读即可裁定 LISTEN 形态;现"连续 2 次"去抖对该形态无必要——
瞬态窗口仅存在于 0~10ms 内,且第二次回读必在窗口外)。
**E2 补充发现(2026-10-13 12:23,Phase 15 板测 TC1501/1502b 实证):LISTEN 态
CLOSE_SOCKET 是二段关闭**。CLOSE 命令对 LISTEN 态 Socket 返回 SUCCESS(0x00),
但只拆监听(TCP 01H→00H),**byte0 恒留 05H(Socket 仍 OPEN),2s 内不自落**;
需再发一次 CLOSE(此时 TCP 已 00H)byte0 才落 00H(二段间隔实测 0ms 即落)。
生产 net 层早已在**无意中吸收**该语义:`net_close_locked` 等 CLOSED 的 500ms 窗
超时后照常放行,随后重 listen 时 `net_listen_locked` 的 Trap 09 open 重试
(3 次 × 500ms 沉降)第二次 open 前的 close 恰好充当二段——这就是 Trap 09
"关闭后需延时才能重开"重试环存在的芯片级原因之一。阶段 2 `sock_reset_poll`
的 WAIT_CLOSE 阶段已内置二段补发(标记=drain 字段 0xF,只补发一次),
TC1502b 实证 LISTEN 态复位 GRACEFUL ~180ms 落定。
**对阶段 3 的含义**:任何以 `cmd_done(DONE_CLOSE)` 为判据的等待,若目标 Socket
可能处于 LISTEN,必须容忍"一次 CLOSE 不落 00H"——要么走 sock_reset(已内置),
要么保留 Trap 09 式重试,不得把 DONE_CLOSE 当单次 CLOSE 的充分条件。
### E3 结果(同场同固件,5 命令 × 5 轮 × 2 遍 = 50 样本,两遍签名逐条一致)
**方法**:发命令前对照读 GET_CMD_STATUS(记录残留假阳性);发命令后按手册
`docs/芯片手册/CH395F.md` §9.2.1 节奏(≥2ms 首查)以 ~1ms 轮询至终态(2s 上限)。
`pre`=对照读值,`first`=首个非 BUSY 终值,`busy`=是否观察到 BUSY→终态转变。
| 命令 | pre(对照读) | busy | first | done | 判别力判定 |
|---|---|---|---|---|---|
| OPEN_SOCKET | 0x00(r0) / **0x17**(r1-4) | 否(0/10) | 0x00 | 3ms | **部分**:状态确被 OPEN 更新(0x17→0x00),但 pre=SUCCESS 时完成与残留不可分 |
| TCP_LISTEN | 0x00(残留 SUCCESS) | 否(0/10) | 0x00 | 3ms | **不成立**:无转变,残留 SUCCESS 不可甄别 |
| CLOSE_SOCKET | 0x00(残留 SUCCESS) | 否(0/10) | 0x00 | 3ms | **不成立**:同上 |
| SET_SOUR_PORT | **0x17** | 否 | **0x17(不变)** | — | **不成立**:SET 类根本不更新命令状态 |
| SET_PROTO_TYPE | **0x17** | 否 | **0x17(不变)** | — | **不成立**:同上 |
**三条实证**:
1. **残留假阳性坐实**:陈旧错误码 0x17(ERR_VAL,源自"对已关闭 Socket 再 close")
跨后续 SET 命令(不更新状态)持续存活——复核 `docs/问题记录/CH395F_Trap_Records.md`
Trap 25 定案轮的"陈旧残留"形态(RESET_ALL 陈旧 BUSY 变体本矩阵未复现,同类
陈旧值持续存活已证)。
2. **OPEN/LISTEN/CLOSE 均在 <2ms 完成**,BUSY 从未观察到——"BUSY→终态"转变对这三条
命令不可观测;驱动 `poll_cmd_status` 20ms 粒度对它们恒白等 ≥20ms(无害但无判别价值)。
3. **SET 类无判别力**(命令状态完全不被更新)——Trap 记录结论复核成立。
**判据结论(定案 `docs/网络/N34-自愈审计/实施方案.md` §4 第 4 项)**:五条命令均不满足
"发后 ≤N ms 变终态 **且** 无残留假阳性" → **`ch395f_cmd_done` 完成判据改用状态回读**:
open 完成=byte0 变 05H;listen 完成=TCP=01H;close 完成=byte0=00H
(回读成本 18.1µs 由 E2 实测背书;listen 可见延迟 ≤10ms 由 E2 矩阵背书,成本与时效均成立)。
GET_CMD_STATUS 仅保留两用途:INIT_CH395 类慢命令(内核前/测试路径)与**命令级被拒**
检测(非 SUCCESS 非 BUSY 错误码仍会被芯片写入命令状态,B2 判据仍有效——被拒码是
"新值覆盖残留"方向,不受残留歧义影响)。`poll_cmd_status` 保留给内核前/测试路径,
产品 socket 路径弃用。
### E4 结果(同场同固件 + 生产路径基线;3 变体 ×10 轮 ×2 遍 = 60 轮)
**方法**:每轮先造污染会话(主机 `test/host/ch395f_reuse_host.py --mode e4`:连上 →
发 3000B → RST,Trap 23 中止形态),芯片侧按变体执行复位序列,**立即**原端口重开
+ LISTEN,主机立即上传 4096B 图案载荷(图案种子随全局轮次变,上一轮残渣必失配)。
PASS 口径 = 消费者在 DISCONNECT/TIM_OUT 前实际读到的字节数=4096 且图案逐字节匹配
(= 生产 net 层释放语义;事后读空仅作取证,不计入 PASS)。
| 变体 | 第 1 遍 | 第 2 遍 | 观察 |
|---|---|---|---|
| A 读空 RX→CLOSE→排事件→等 byte0=00H | **10/10** | **10/10** | 19/20 轮 rxdrain=**2048**(残渣恰等于芯片单 socket RX 缓冲整容 = Trap 23 机制直接证据) |
| B CLEAR_RECV_BUF→CLOSE→排事件→等 CLOSED | **10/10** | **10/10** | 与 A 等价,无差异 |
| C 什么都不做→CLOSE→等 CLOSED | **0/10** | **0/10** | 首 C 轮(rg20)两遍同签名,随后**自持级联** |
**C 变体失败签名(两遍逐字节复现)**:重开后主机载荷连接 SYN 被吞(主机侧
connect 超时);bench 首次 SINT 读 = **0x04**(陈旧 RECV 位粘滞——Trap 14
"粘滞到被读",close/open 不清 SINT);后续轮污染连接亦 SYN 被吞(主机
`contam CONNECT timeout`、bench `no death event`)——每轮 close 又携带未排空数据
→ **级联自持**,open+listen 命令照常返回 SUCCESS 也无法恢复,唯芯片硬件复位
(E13 RSTI←NRST)清除。
**机制定案**:决定性一步 = **close 前 RX 缓冲必须为空**(读空与 CLEAR_RECV_BUF
等价——Trap 25"缓冲重分配无效"指的是 set_send/recv_buf 重分配,不是 CLEAR)。
带非空 RX 关闭违反 `docs/芯片手册/CH395F.md` §5.52 bit3=1"读出残留数据后再关闭"
契约 → 芯片拆链停滞 → 下一会话 SYN 被吞/CONNECT 丢失,且自持。排空事件(A/B 有、
C 无)清的是粘滞 SINT 位——对**事件驱动 accept 的正确性**必需(0x04 陈旧 RECV 会
误导消费者),但不是 TCP 层吞 SYN 的根因。所有轮 closed_ms=0(close 命令落定后
byte0 已是 00H)——"等 CLOSED"几乎零成本,但为契约必需步。
**生产路径基线**(烧 bench 固件前,Phase 1.5 产品固件 Code=209780):
`MDK-ARM/ftp_abort_probe.py --check-abort --rounds 5` → **5/5**(中止 STOR→450;
设备日志 `sock4 TIMEOUT` → quarantine → `UPLOAD '/ab000N.bin' FAILED` →
followup `UPLOAD '/ab_ok.bin' 4096 bytes OK`)——现实现(隔离期持续排空 RX +
close + 排空事件 + 等 CLOSED)行为基线全绿,与变体 A 序列一致。
**判据结论(定案 `docs/网络/N34-自愈审计/实施方案.md` §4 第 3 项)**:
(a) 与现实现等价成立(A 20/20 载荷完整);(b) B 与 A 等价(无差异记录);
C 不等价(0/20 + 级联)→ **`ch395f_sock_reset` 内部序列定案**:
1. 读空 RX(GET_RECV_LEN→READ_RECV_BUF 直到 0;CLEAR_RECV_BUF 等价可用,**取读空**
——保 §5.52 契约且排空字节数可观测可留痕);
2. CLOSE_SOCKET;
3. 排空本 socket 事件(drain-until-quiescent,E8 M5 口径:连续两轮无新位);
4. 轮询 byte0=00H(非阻塞状态机步进,约束不变)。
GRACEFUL 与 QUARANTINE **都必须排 RX**——E4 假设"差异仅在是否排 RX + 最短等待"中
"是否排 RX"一半被否(带脏缓冲关闭在任何释放形态下都危险),两模式差异只剩
最短等待(100ms/400ms,Trap 23 二阶段实测值)。