Files
STM32F4-Base/docs/测试说明/m2_data/README.md
T
wandering1 d1e6bb4ba7 W5波+N-19收口:FTP鉴权落地、Trap25三连定案修复(N-30)、N-20/N-23/N-26
N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
  (user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
  出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13

N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
  FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
  relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
  幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
  (芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
  (不注册编译;实验分支 n30-chip-bench 保留)

N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言

验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
2026-10-11 18:50:24 +08:00

121 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M2 链路延迟实测数据(Phase 13,安静档)
本目录保存 M2(Phase 13:芯片 + 队列时延基线)的**原始实测产物**。判定阈值与解读见
[`../链路延迟测试说明.md`](../链路延迟测试说明.md) §6.2;缺陷总表见 `docs/测试说明/链路延迟测试说明.md` §8。
## 1. 运行元数据
| 项 | 值 |
|---|---|
| 日期 | 2026-09-22(设备 RTC 显示 2026-09-21,落后 1 天,仅显示差异;主机时间戳 = 设备 + 4s) |
| 台架 | COM6 @115200;目标 192.168.1.100:8080(Phase 13 独占 socket 2) |
| 固件 | `test/board/test_config.h` = `TEST_SUITE_CH395F`;`test/board/ch395f_test.h` = `ENABLE_PHASE13_TESTS`(仅此一项) |
| 构建 | `keil-build` skill(`keil_build.py`)→ **0 错误 0 警告**(测试构建与产品构建均 0/0) |
| 对端 | `.venv\Scripts\python.exe test\latency_peer.py --mode net`(纯标准库,`--wait 170`) |
| 会话顺序 | HELLO → L5_RECV → L5_SEND → L3 → L10 → L6 → L7 → DONE |
| 干扰 | 无(安静档,`ftp_stress=0`;未跑 `--ftp-stress`) |
| PASS 轮次 | **run12 / run13 / run15** 三次独立完整 PASS(`summary verdict=OK`、`=== Phase 13: 1/1 PASSED (failed=0) ===`、peer exit 0) |
复现命令(顺序不可反:先 `clear` 再起 peer,最后烧录):
```powershell
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py
& '.venv\Scripts\python.exe' .dsh\skills\serial-assistant\scripts\serial_tool.py clear
& '.venv\Scripts\python.exe' test\latency_peer.py --host 192.168.1.100 --port 8080 `
--json "docs\测试说明\m2_data\m2_quiet_runNN.json" --wait 170 # 后台作业
& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py flash
& '.venv\Scripts\python.exe' .dsh\skills\serial-assistant\scripts\serial_tool.py wait-idle `
--timeout 120 --settle-ms 10000 --max-ms 110000
# 判定:Grep .dsh\skills\serial-assistant\scripts\state\serial.log
```
判定标记:Required `App init OK` / `Network Init` / `net init: OK` / `[LAT] report complete` /
`=== Phase 13: 1/1 PASSED`;Forbidden `HardFault` / `assert` / `[ERR]` / `[FAIL]` / `verdict=FAIL`;
peer 侧退出码 **0** = PASS(收到 `0xFF` 并打印汇总,`l7_crc.fail == 0`)。
## 2. 产物清单
| 文件 | 内容 |
|---|---|
| `m2_quiet.json` | **run15**(最终代码,规范基线)peer 端原始 JSON,含 10 帧逐帧批次明细 |
| `m2_quiet_run13.json` | **run13**(PASS 复现)peer 端原始 JSON |
| `m2_quiet_run14.json` | **run14**(PASS;但该轮 MCU 侧探针日志过载,仅 peer 侧数据有效,见 §6) |
| `m2_serial_excerpt_run15.txt` | **run15** 串口证据片段 62 行(**只含烧录重启后的会话**:从 Phase 13 横幅/`run_id` 校准行到 `1/1 PASSED` + relisten) |
| `m2_serial_excerpt_run13.txt` | run13 串口日志中 `[LAT]`/`[NET]`/Phase 13 相关 87 行(含烧录前旧固件段,需自行忽略) |
## 3. 实测结果
### 3.1 MCU 侧(`[LAT]` 报告,三次 PASS)
| 段 | run12 med(min/max, n) | run13 med(min/max, n) | **run15 med(min/max, n)** | warn / crit |
|---|---|---|---|---|
| `queue_rt_recv` | 6014µs(5365/6020, 19) | 6007µs(5392/6025, 20) | **5997µs(5513/6033, 20)** | 10ms / 100ms |
| `queue_rt_send` | 986µs(836/1204, 20) | 987µs(833/1209, 20) | **987µs(838/1209, 20)** | 10ms / 100ms |
| `chunk_wait` | 235µs(215/238, 64) | 219µs(213/377, 64) | **219µs(214/381, 64)** | 10ms / 500ms(spike) |
| `logtax_line` | 4396µs | 4396µs(4390/4414) | **4396µs(4394/4422)** | 10ms / 25ms |
| `req2first_mcu` | 310µs(296/338, 10) | 318µs(263/361, 10) | **319µs(308/338, 10)** | 20ms / 200ms |
| `fullframe_mcu` | 6021µs(5986/6103, 10) | 6052µs(5966/6078, 10) | **6028µs(5991/6066, 10)** | 50ms / 500ms |
三轮均:6 段 `verdict=OK`、`spikes=0`、`summary verdict=OK`、`1/1 PASSED`。
> run12 的 `queue_rt_recv` n=19 而非 20:对端 20×100B 中相邻两包被 TCP 合并成一次收
> (完成判定按字节 2000B),属正常合并,非丢包(三轮字节数均为 2000)。
### 3.2 PC 侧端到端(peer JSON)
| 段 | run12 med(min/max) | run13 med(min/max) | run15 med(min/max) | CRC |
|---|---|---|---|---|
| L6 端到端(op→回显) | 12.5ms(5.5/16.0) | 13.8ms(5.9/16.0) | 8.9ms(6.3/16.0) | — |
| L7 首字节 | 10.9ms(7.9/16.2) | 11.8ms(7.5/17.7) | 11.3ms(7.8/16.5) | — |
| L7 全帧 3209B | 61.1ms(54.2/61.5) | 61.7ms(59.9/70.9) | 57.9ms(52.6/72.3) | 10/0 |
## 4. 关键发现:L7 尾批固定迟到 ~44~60ms
run15 逐帧明细(10/10 帧结构完全一致):
```
frame#1: first=11.620ms batches=[1024,1024,1024,137] tail_lag=+53.8ms
frame#2: first=11.327ms batches=[1024,1024,1024,137] tail_lag=+46.5ms
frame#3: first= 8.160ms batches=[1024,1024,1024,137] tail_lag=+46.5ms
frame#4: first= 7.773ms batches=[1024,1024,1024,137] tail_lag=+44.8ms
frame#5: first= 9.858ms batches=[1024,1024,1024,137] tail_lag=+53.9ms
frame#6: first=11.900ms batches=[1024,1024,1024,137] tail_lag=+43.8ms
frame#7: first=10.465ms batches=[1024,1024,1024,137] tail_lag=+44.2ms
frame#8: first=10.615ms batches=[1024,1024,1024,137] tail_lag=+43.4ms
frame#9: first=11.328ms batches=[1024,1024,1024,137] tail_lag=+60.2ms
frame#10:first=16.522ms batches=[1024,1024,1024,137] tail_lag=+55.7ms
```
- 前 3 批各 1024B 在 **~4ms** 内到齐;第 4 批 137B(=3209−3072)稳定落在 **+43~+60ms**;
- MCU 侧把整个 3209B 交给芯片只花 **6.0ms**(`fullframe_mcu`)→ 延迟**不在 MCU 发送路径**;
- 缺口在**芯片 TCP 尾段发送 / 对端 ACK 交互**(候选:Nagle 式小段等待 + 对端延迟 ACK);
- 该尾批**主导整帧时长**(total ≈ 首字节 + 尾批延迟),是远端显示"每帧多 ~50ms"的直接来源;
- **M3 待办**:Wireshark(`tcp.port==8080`)确认尾段是被芯片扣住还是被对端 ACK 拖住,再定对策
(对端 `TCP_NODELAY` / 帧长与 chunk 对齐),**未证实前不改协议**。
## 5. 结论(回答 M2 立项问题)
1. **安静档不存在 500ms 台阶**:三轮 6 段全 OK、零尖峰、p95≈med;
2. 会话级 MCU 净成本量级 **~6ms**(`queue_rt_recv`,与 netTask 轮询节拍同量级);
3. 芯片 chunk 级不是瓶颈:`chunk_wait` med 219µs ≈ 每 chunk SPI 成本(1.61ms)的 1/7;
4. 生产链路的可见延迟主要在 **PC/线路段**(L6:MCU 侧 0.32ms vs 端到端 8.9~13.8ms)
与 **L7 尾批 ~50ms**。
## 6. 测量方法学(两条必须记住的坑)
1. **探针不得在 net 热路径逐调用打日志**(run14 实证):在 `net_wait_result` 内加
`pick/block` 两行后,日志量 40KB → 1.04MB(9,644/9,779 行 = **98.6%**),115200 下
丢行/串行错位,冲掉 `[LAT]` 段证据,`wait-idle` 永远判不出空闲;并实测把
`queue_rt_send` med 从 987µs 抬到 **7685µs(7.8×)**、`queue_rt_recv` p95 抬到 21ms。
→ 该轮 MCU 侧数据**不作基线**;诊断需求改在 `[LAT]` 段报告侧聚合。
2. **首连必失败是有意为之的正常现象**:peer 首连时常在 MCU 启动期完成握手,随后芯片
空闲超时(15~30s 无数据)RST → `WinError 10054`;peer 自动 +2s 重连后会话正常
(run12/13/15 均如此)。**另注意**:首连时若 MCU 正在烧录,attempt1 由**上一版固件**
服务(日志里那段偏高的数据不属于本轮固件),只有烧录重启后的会话才计入本轮基线。
## 7. 未纳入本目录的数据
- run1~run11 为缺陷定位过程(D11~D16 见 `docs/测试说明/链路延迟测试说明.md` §6.1),其中 run10/run11 的 L7 失败、
run9 的 170s 连接拒绝均已定位并修复;
- 压力档(`--ftp-stress`,E-02 复现)与 `--mode remo`(生产 RemoDispBus 客户端)属 M3。