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
+68 -2
View File
@@ -1,8 +1,13 @@
# N-30 芯片级复用时序台架:主机端(与 test/board/ch395f_reuse_bench.c 共用变体表)
# 用法: python ch395f_reuse_host.py [--host IP] [--cycles N]
# 纯 TCP,无 FTP。按 idx 轮转连接 5000+idx 端口,记录收发结果与时刻。
# 用法: python ch395f_reuse_host.py [--host IP] [--cycles N] [--mode legacy|e4]
# legacy: 按 idx 轮转连接 5000+idx 端口,记录收发结果与时刻。
# e4: N34 E4 sock_reset A/B/C 矩阵配套(2026-10-13):每轮两次连接——
# ①污染:连上发 3000B 后 RST(SO_LINGER 0,Trap 23 中止形态);
# ②载荷:立即重连发 4096B 图案(pat[i]=(seed+i)&0xFF, seed=(rg*97+13)&0xFF)后 FIN。
# 端口 5100+rg,rg=0..(3*rounds-1),变体顺序 A/B/C(与固件 bench 表一致)。
import argparse
import socket
import struct
import sys
import time
@@ -70,12 +75,73 @@ def run_round(host, idx, tx_len, close_mode):
return ok
def connect_retry(host, port, budget_s):
"""connect with retry until budget_s elapses; None on give-up"""
t0 = time.time()
while time.time() - t0 < budget_s:
try:
return socket.create_connection((host, port), timeout=5)
except OSError:
time.sleep(0.2)
return None
def e4_round(host, rg, rounds_per_variant, first_budget):
"""one E4 round: contaminate (send 3000B then RST) + payload (4096B pattern then FIN)"""
port = 5100 + rg
seed = (rg * 97 + 13) & 0xFF
budget = first_budget if rg == 0 else 30
s = connect_retry(host, port, budget)
if s is None:
print("%s E4 r%2d port%5d <<<< contam CONNECT timeout" % (ts(), rg, port))
return False
try:
s.sendall(b"\x33" * 3000)
except OSError as e:
print("%s E4 r%2d contam send err %r" % (ts(), rg, e))
try:
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", 1, 0))
except OSError:
pass
s.close() # RST: abort mid-session like ftp_abort_probe (Trap 23 form)
time.sleep(0.05)
s = connect_retry(host, port, 20)
if s is None:
print("%s E4 r%2d port%5d <<<< payload CONNECT timeout" % (ts(), rg, port))
return False
payload = bytes(((seed + i) & 0xFF) for i in range(4096))
try:
s.sendall(payload)
except OSError as e:
print("%s E4 r%2d payload send err %r" % (ts(), rg, e))
s.close()
return False
s.close() # FIN: full payload delivered, chip drains
print("%s E4 r%2d var=%s port%5d contam+payload sent (seed=%02X)"
% (ts(), rg, "ABC"[rg // rounds_per_variant], port, seed))
return True
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--host", default="192.168.1.100")
ap.add_argument("--cycles", type=int, default=3)
ap.add_argument("--mode", choices=["legacy", "e4"], default="legacy")
ap.add_argument("--rounds", type=int, default=10, help="e4: rounds per variant")
ap.add_argument("--first-budget", type=int, default=300,
help="e4: connect budget for round 0 (bench runs E2/E3 first)")
args = ap.parse_args()
if args.mode == "e4":
fails = []
total = 3 * args.rounds
for rg in range(total):
if not e4_round(args.host, rg, args.rounds, args.first_budget):
fails.append(rg)
print("E4 RESULT: %d/%d host-side ok, failures %s" % (total - len(fails), total, fails))
return 1 if fails else 0
fails = []
for c in range(args.cycles):
for idx in sorted(VARS):