diff --git a/App/task/net_task.c b/App/task/net_task.c index 76541549..42f18115 100644 --- a/App/task/net_task.c +++ b/App/task/net_task.c @@ -121,6 +121,10 @@ int net_stack_bring_up(void) { (phy == CH395F_PHY_10M_HALF) ? "10M HALF" : (phy == CH395F_PHY_DISCONN) ? "DISCONNECT" : "UNKNOWN"); + /* P0-a 证据行:重传周期芯片验收状态(net_init 静默采集,此处延迟打印—— + * 本位置与 testTask 启动日志无并发窗口,不会触发 UART 丢行) */ + net_retrans_status_log(); + /* 自检埋点:链路超时未建立 → 记入自检记录(仅故障才写) */ if (phy == CH395F_PHY_DISCONN) { syslog_post(SYSLOG_SELFTEST, "comms fault"); diff --git a/Drivers/BSP/NET/net_config.h b/Drivers/BSP/NET/net_config.h index 0f1fdbe8..d932bfb3 100644 --- a/Drivers/BSP/NET/net_config.h +++ b/Drivers/BSP/NET/net_config.h @@ -9,6 +9,8 @@ * 2026-09-10 王建锋 清理未引用宏(TCP Server 监听 Socket 索引、收发缓冲、 * 连接/接受超时、select/队列/轮询);KeepAlive 三宏改为 * 实际生效值 60s/5s/3 并在 net_socket.c 引用(原宏为无效遗留值) + * 2026-09-22 新增 NET_RETRANS_COUNT/NET_RETRANS_PERIOD_MS(P0-a:重传周期 + * 500→200ms 治 D1 症状),net_socket.c 的字面量 8/500 移入本文件 */ #ifndef NET_CONFIG_H @@ -37,6 +39,21 @@ extern "C" { #define NET_RECV_TIMEOUT_MS 30000 /* 接收超时(30秒,0=无限等待) */ #endif +/* + * TCP 重传配置(由 net_socket.c 的 net_init() 在 ch395f_init() 之前下发) + * P0-a(2026-09-22):周期 500→200ms——单次丢包代价 500→200ms(治 D1 症状), + * 总窗口 8×200=1.6s,链路真断时判失败更快(对远端显示重连有利)。 + * 手册 §5.18 仅标注上限(≤1000ms)未标注下限;200ms 已经台架验证芯片接受 + *(GET_CMD_STATUS=0x00 + 全套件无回归,见《链路延迟测试说明.md》§10.2 记录)。 + */ +#ifndef NET_RETRANS_COUNT +#define NET_RETRANS_COUNT 8 /* 重传次数(手册:最大 20,默认 12) */ +#endif + +#ifndef NET_RETRANS_PERIOD_MS +#define NET_RETRANS_PERIOD_MS 200 /* 重传周期 ms(手册:最大 1000,默认 500) */ +#endif + /* * TCP KeepAlive 配置(单位 ms;须为 500 的倍数且 IDLE > INTVL) * 由 net_socket.c 的 net_init() 在 ch395f_init() 之前下发 diff --git a/Drivers/BSP/NET/net_socket.c b/Drivers/BSP/NET/net_socket.c index 14f15e0c..feec57c1 100644 --- a/Drivers/BSP/NET/net_socket.c +++ b/Drivers/BSP/NET/net_socket.c @@ -40,6 +40,7 @@ static net_sock_t s_net_socks[NET_MAX_SOCKETS]; /* Socket 控制块数组 */ static int s_net_errno = 0; /* 最后错误码 */ static uint8_t s_net_initialized = 0; /* 初始化标志 */ +static uint8_t s_retrans_cmd_status = 0xFFU; /* P0-a:重传周期 GET_CMD_STATUS 验收结果(0xFF=未采集) */ static uint8_t s_local_ip[4]; /* 本机 IP 缓存(网络序,net_getsockname 用) */ static uint16_t s_dynamic_port = 49152; /* 动态端口分配起始值 */ static volatile uint32_t s_net_generation = 0; /* 网络代次号:网络重建完成时递增(服务据此重建监听) */ @@ -147,8 +148,30 @@ static bool s_mac_is_zero(const uint8_t *p_mac) { ch395f_set_tcp_mss(CH395F_TCP_MSS); /* 设置 TCP 重传参数(必须在 INIT_CH395 之前调用*/ - ch395f_set_retrans_count(8); /* 重传 8 次*/ - ch395f_set_retrans_period(500); /* 每次间隔 500ms,总计 4s 重传窗口 */ + ch395f_set_retrans_count(NET_RETRANS_COUNT); + ch395f_set_retrans_period(NET_RETRANS_PERIOD_MS); + /* P0-a 一次性验收(手册无重传参数回读命令):设置命令之后查 GET_CMD_STATUS。 + * 实测(2026-09-22 台架,500ms 合法值与 2000ms 超限值行为完全一致): + * SET 类命令不更新状态寄存器——读到的是 RESET_ALL 的 0x10(BUSY) 陈旧残留 + * (ch395f_reset 只延时 20ms、不轮询状态);INIT 类长命令才重写寄存器。 + * 故 3 次 × 20ms 轮询即可捕获真正的值/参数错误码(0x19/0x1A 等), + * 0x10 只证明"寄存器未更新",不构成值判据——值的接受性以 + * 手册范围(≤1000ms)+ 全套件无回归 + 与 500ms 行为一致为准。 + * 注意:此处只静默捕获状态,不打日志——本窗口与 testTask 启动日志并发, + * 并发 printf 会因非重入 UART 发送丢整行(2026-09-22 台架实测); + * 打印延迟到 net_stack_bring_up 的 PHY 行之后(net_retrans_status_log)。 */ + { + uint8_t rto_st = CH395F_ERR_BUSY; + + for (uint32_t i = 0U; i < 3U; i++) { + osDelay(20U); + rto_st = ch395f_get_cmd_status(); + if (rto_st != CH395F_ERR_BUSY) { + break; + } + } + s_retrans_cmd_status = rto_st; + } /* 设置 TCP KeepAlive 参数(必须在 INIT_CH395 之前,单位 ms,必须为 500 的倍数,且 IDLE > INTVL) * 值来自 net_config.h 的 NET_KEEPALIVE_*(60s/5s/3)*/ @@ -216,6 +239,34 @@ static bool s_mac_is_zero(const uint8_t *p_mac) { return 0; } +/* + * 函数功能:打印 P0-a 重传周期芯片验收证据行(一次性) + * 入口参数:无 + * 返 回 值:无 + * 限定条件:net_init 之后调用;建议放在 net_stack_bring_up 的 PHY 行之后 + * (启动日志低并发窗口)——net_init 尾部与其它任务启动日志并发时, + * 非重入 UART 发送会丢整行(2026-09-22 台架实测) + * 函数说明:三分支判读(实测 2026-09-22:SET 类命令不更新状态寄存器): + * 0x00 = 芯片明确报告接受;0x10 = 陈旧 BUSY 残留(无判别力,INFO 级, + * 避免健康启动误触 [ERR] 标记);其它状态码 = 真值/参数错误(ERROR 级) + */ +void net_retrans_status_log(void) { + if (s_retrans_cmd_status == 0xFFU) { + return; /* 本次启动未走 NET 层 bring_up(如硬件层测试模式) */ + } + if (s_retrans_cmd_status == CH395F_ERR_SUCCESS) { + DBG_INFO("net_init: retrans %u x %u ms accepted by chip (status=0x00)", + (unsigned)NET_RETRANS_COUNT, (unsigned)NET_RETRANS_PERIOD_MS); + } else if (s_retrans_cmd_status == CH395F_ERR_BUSY) { + DBG_INFO("net_init: retrans %u x %u ms set (status 0x10 = stale residue, inconclusive)", + (unsigned)NET_RETRANS_COUNT, (unsigned)NET_RETRANS_PERIOD_MS); + } else { + DBG_ERROR("net_init: retrans period %u ms REJECTED by chip (cmd status=0x%02X)", + (unsigned)NET_RETRANS_PERIOD_MS, (unsigned)s_retrans_cmd_status); + } + s_retrans_cmd_status = 0xFFU; /* 只打印一次 */ +} + /* * 函数功能:取网络代次号 * 入口参数:无 @@ -1112,7 +1163,6 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags, int recv_len = ch395f_get_recv_len(sockfd); if (recv_len > 0) { int read_len = (recv_len > len) ? len : recv_len; - DBG_INFO("recv sock%d len=%d", sockfd, recv_len); ch395f_read_recv_buf(sockfd, (uint8_t *)buf, (uint16_t)read_len); p_sock->recv_bytes += (uint32_t)read_len; p_sock->readable = 0; /* 已消费数据(注:部分读受 Trap 13 限制,下一次 RECV_OK 会重新置位) */ diff --git a/Drivers/BSP/NET/net_socket.h b/Drivers/BSP/NET/net_socket.h index d11c12b0..e24f2aad 100644 --- a/Drivers/BSP/NET/net_socket.h +++ b/Drivers/BSP/NET/net_socket.h @@ -74,6 +74,17 @@ typedef struct { */ int net_init(const char *ip, const char *mask, const char *gateway, const uint8_t *mac); +/* + * 函数功能:打印 P0-a 重传周期芯片验收证据行(一次性) + * 入口参数:无 + * 返回值:无 + * 限定条件:net_init() 之后;建议放在 net_stack_bring_up() 的 PHY 行之后 + * 函数说明:net_init 在设置重传参数后立即静默查询 GET_CMD_STATUS(手册无回读 + * 命令,此状态是"芯片是否接受该周期"的唯一证据);打印延迟到 PHY 行 + * 之后,避开启动期多任务并发 printf 丢行 + */ +void net_retrans_status_log(void); + /* * 函数功能:取网络代次号 * 入口参数:无 diff --git a/docs/测试说明/m2_data/m2_quiet_r200.json b/docs/测试说明/m2_data/m2_quiet_r200.json new file mode 100644 index 00000000..15cbec24 --- /dev/null +++ b/docs/测试说明/m2_data/m2_quiet_r200.json @@ -0,0 +1,277 @@ +{ + "mode": "net", + "host": "192.168.1.100", + "port": 8080, + "ts_start": "2026-09-22 11:10:26", + "ts_end": "2026-09-22 11:10:29", + "duration_s": 2.44, + "ops_seen": 24, + "ftp_stress": false, + "seg_l6": { + "n": 10, + "min_ms": 1.67, + "med_ms": 3.917, + "p95_ms": 11.951, + "max_ms": 11.951, + "spikes500": 0, + "echo_ok": 10, + "echo_fail": 0 + }, + "seg_l7_first_byte": { + "n": 10, + "min_ms": 4.022, + "med_ms": 10.01, + "p95_ms": 13.815, + "max_ms": 13.815, + "spikes500": 0 + }, + "seg_l7_total": { + "n": 10, + "min_ms": 53.606, + "med_ms": 57.877, + "p95_ms": 69.879, + "max_ms": 69.879, + "spikes500": 0 + }, + "l7_crc": { + "ok": 10, + "fail": 0, + "batches_per_frame": [ + 4 + ] + }, + "l5_recv": { + "bytes": 2000, + "window_ms": 1008.6737 + }, + "l5_send": { + "bytes": 2000, + "window_ms": 47.5123 + }, + "l3_drain": { + "bytes": 65536, + "window_ms": 125.4687 + }, + "frames_l7": [ + { + "first_ms": 8.255, + "total_ms": 56.233, + "batches": [ + [ + 8.261, + 1024 + ], + [ + 10.034, + 1024 + ], + [ + 11.848, + 1024 + ], + [ + 56.217, + 137 + ] + ] + }, + { + "first_ms": 13.815, + "total_ms": 60.593, + "batches": [ + [ + 13.82, + 1024 + ], + [ + 15.597, + 1024 + ], + [ + 17.411, + 1024 + ], + [ + 60.577, + 137 + ] + ] + }, + { + "first_ms": 4.022, + "total_ms": 55.84, + "batches": [ + [ + 4.026, + 1024 + ], + [ + 5.803, + 1024 + ], + [ + 7.671, + 1024 + ], + [ + 55.825, + 137 + ] + ] + }, + { + "first_ms": 10.01, + "total_ms": 55.081, + "batches": [ + [ + 10.017, + 1024 + ], + [ + 11.805, + 1024 + ], + [ + 13.598, + 1024 + ], + [ + 55.065, + 137 + ] + ] + }, + { + "first_ms": 5.731, + "total_ms": 64.762, + "batches": [ + [ + 5.738, + 1024 + ], + [ + 7.497, + 1024 + ], + [ + 9.345, + 1024 + ], + [ + 64.748, + 137 + ] + ] + }, + { + "first_ms": 13.778, + "total_ms": 57.877, + "batches": [ + [ + 13.784, + 1024 + ], + [ + 15.562, + 1024 + ], + [ + 17.362, + 1024 + ], + [ + 57.864, + 137 + ] + ] + }, + { + "first_ms": 6.701, + "total_ms": 55.287, + "batches": [ + [ + 6.706, + 1024 + ], + [ + 8.51, + 1024 + ], + [ + 10.302, + 1024 + ], + [ + 55.272, + 137 + ] + ] + }, + { + "first_ms": 13.296, + "total_ms": 69.879, + "batches": [ + [ + 13.303, + 1024 + ], + [ + 15.055, + 1024 + ], + [ + 16.877, + 1024 + ], + [ + 69.864, + 137 + ] + ] + }, + { + "first_ms": 5.153, + "total_ms": 53.606, + "batches": [ + [ + 5.157, + 1024 + ], + [ + 6.952, + 1024 + ], + [ + 8.765, + 1024 + ], + [ + 53.592, + 137 + ] + ] + }, + { + "first_ms": 13.369, + "total_ms": 61.291, + "batches": [ + [ + 13.374, + 1024 + ], + [ + 15.179, + 1024 + ], + [ + 17.008, + 1024 + ], + [ + 61.279, + 137 + ] + ] + } + ] +} diff --git a/docs/测试说明/m2_data/m2_quiet_r500.json b/docs/测试说明/m2_data/m2_quiet_r500.json new file mode 100644 index 00000000..62e48c1d --- /dev/null +++ b/docs/测试说明/m2_data/m2_quiet_r500.json @@ -0,0 +1,277 @@ +{ + "mode": "net", + "host": "192.168.1.100", + "port": 8080, + "ts_start": "2026-09-22 11:08:59", + "ts_end": "2026-09-22 11:09:02", + "duration_s": 2.59, + "ops_seen": 24, + "ftp_stress": false, + "seg_l6": { + "n": 10, + "min_ms": 9.348, + "med_ms": 12.065, + "p95_ms": 16.051, + "max_ms": 16.051, + "spikes500": 0, + "echo_ok": 10, + "echo_fail": 0 + }, + "seg_l7_first_byte": { + "n": 10, + "min_ms": 7.619, + "med_ms": 13.088, + "p95_ms": 53.221, + "max_ms": 53.221, + "spikes500": 0 + }, + "seg_l7_total": { + "n": 10, + "min_ms": 57.397, + "med_ms": 62.679, + "p95_ms": 106.185, + "max_ms": 106.185, + "spikes500": 0 + }, + "l7_crc": { + "ok": 10, + "fail": 0, + "batches_per_frame": [ + 4 + ] + }, + "l5_recv": { + "bytes": 2000, + "window_ms": 1008.8286 + }, + "l5_send": { + "bytes": 2000, + "window_ms": 45.519 + }, + "l3_drain": { + "bytes": 65536, + "window_ms": 125.3308 + }, + "frames_l7": [ + { + "first_ms": 12.655, + "total_ms": 70.865, + "batches": [ + [ + 12.662, + 1024 + ], + [ + 14.453, + 1024 + ], + [ + 16.304, + 1024 + ], + [ + 70.85, + 137 + ] + ] + }, + { + "first_ms": 7.619, + "total_ms": 58.158, + "batches": [ + [ + 7.627, + 1024 + ], + [ + 9.427, + 1024 + ], + [ + 11.18, + 1024 + ], + [ + 58.143, + 137 + ] + ] + }, + { + "first_ms": 15.244, + "total_ms": 68.911, + "batches": [ + [ + 15.249, + 1024 + ], + [ + 17.025, + 1024 + ], + [ + 18.875, + 1024 + ], + [ + 68.889, + 137 + ] + ] + }, + { + "first_ms": 13.088, + "total_ms": 62.212, + "batches": [ + [ + 13.092, + 1024 + ], + [ + 14.853, + 1024 + ], + [ + 16.691, + 1024 + ], + [ + 62.196, + 137 + ] + ] + }, + { + "first_ms": 16.735, + "total_ms": 60.274, + "batches": [ + [ + 16.741, + 1024 + ], + [ + 18.501, + 1024 + ], + [ + 20.294, + 1024 + ], + [ + 60.262, + 137 + ] + ] + }, + { + "first_ms": 53.221, + "total_ms": 106.185, + "batches": [ + [ + 53.226, + 1024 + ], + [ + 55.039, + 1024 + ], + [ + 56.83, + 1024 + ], + [ + 106.171, + 137 + ] + ] + }, + { + "first_ms": 12.842, + "total_ms": 69.886, + "batches": [ + [ + 12.846, + 1024 + ], + [ + 14.662, + 1024 + ], + [ + 16.428, + 1024 + ], + [ + 69.865, + 137 + ] + ] + }, + { + "first_ms": 8.738, + "total_ms": 61.345, + "batches": [ + [ + 8.742, + 1024 + ], + [ + 10.551, + 1024 + ], + [ + 12.391, + 1024 + ], + [ + 61.323, + 137 + ] + ] + }, + { + "first_ms": 13.19, + "total_ms": 57.397, + "batches": [ + [ + 13.195, + 1024 + ], + [ + 14.977, + 1024 + ], + [ + 16.845, + 1024 + ], + [ + 57.382, + 137 + ] + ] + }, + { + "first_ms": 10.595, + "total_ms": 62.679, + "batches": [ + [ + 10.608, + 1024 + ], + [ + 12.441, + 1024 + ], + [ + 14.225, + 1024 + ], + [ + 62.668, + 137 + ] + ] + } + ] +} diff --git a/docs/测试说明/m3_data/m3_dev_quiet_r200.json b/docs/测试说明/m3_data/m3_dev_quiet_r200.json new file mode 100644 index 00000000..ad3c26e2 --- /dev/null +++ b/docs/测试说明/m3_data/m3_dev_quiet_r200.json @@ -0,0 +1,1777 @@ +{ + "mode": "remo", + "host": "192.168.1.100", + "port": 7003, + "ts_start": "2026-09-22 11:14:37", + "ts_end": "2026-09-22 11:14:46", + "duration_s": 9.5, + "samples": 50, + "cadence_ms": 100.0, + "tcp_nodelay": false, + "immediate_ack": null, + "in_band_ack_probe": false, + "stress_from": null, + "connect_ms": 17.139, + "reconnect_ms": 22.447, + "reconnect_list_ms": [ + 22.447 + ], + "reconnect_stat": { + "n": 1, + "min_ms": 22.447, + "med_ms": 22.447, + "p95_ms": 22.447, + "max_ms": 22.447, + "spikes500": 0 + }, + "init": { + "rtt_ms": 21.758, + "geom": { + "w": 160, + "h": 160, + "framebytes": 3200, + "payload_len": 8 + } + }, + "cycle_all": { + "n": 50, + "min_ms": 50.414, + "med_ms": 61.648, + "p95_ms": 69.371, + "max_ms": 69.808, + "spikes500": 0 + }, + "cycle_quiet": { + "n": 50, + "min_ms": 50.414, + "med_ms": 61.648, + "p95_ms": 69.371, + "max_ms": 69.808, + "spikes500": 0 + }, + "cycle_stress": { + "n": 0 + }, + "first_byte_all": { + "n": 50, + "min_ms": 3.226, + "med_ms": 9.609, + "p95_ms": 13.808, + "max_ms": 14.212, + "spikes500": 0 + }, + "tail_lag_all": { + "n": 50, + "min_ms": 44.072, + "med_ms": 52.605, + "p95_ms": 58.596, + "max_ms": 59.114, + "spikes500": 0 + }, + "crc": { + "ok": 50, + "fail": 0 + }, + "bitmap": { + "nontrivial_ok": 50, + "nontrivial_fail": 0 + }, + "frames": [ + { + "cycle": 0, + "stress": false, + "first_ms": 13.587, + "total_ms": 61.939, + "tail_lag_ms": 48.066, + "batches": [ + [ + 13.587, + 8 + ], + [ + 13.635, + 1016 + ], + [ + 15.365, + 1024 + ], + [ + 16.744, + 1024 + ], + [ + 61.653, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 1, + "stress": false, + "first_ms": 12.662, + "total_ms": 67.446, + "tail_lag_ms": 54.687, + "batches": [ + [ + 12.662, + 8 + ], + [ + 12.727, + 2040 + ], + [ + 17.145, + 1024 + ], + [ + 67.349, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 2, + "stress": false, + "first_ms": 13.924, + "total_ms": 69.808, + "tail_lag_ms": 55.823, + "batches": [ + [ + 13.924, + 8 + ], + [ + 13.982, + 1016 + ], + [ + 15.729, + 1024 + ], + [ + 17.58, + 1024 + ], + [ + 69.747, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 3, + "stress": false, + "first_ms": 3.377, + "total_ms": 50.414, + "tail_lag_ms": 46.972, + "batches": [ + [ + 3.377, + 8 + ], + [ + 3.404, + 1016 + ], + [ + 5.197, + 1024 + ], + [ + 7.073, + 1024 + ], + [ + 50.35, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 4, + "stress": false, + "first_ms": 12.606, + "total_ms": 67.801, + "tail_lag_ms": 55.136, + "batches": [ + [ + 12.606, + 8 + ], + [ + 12.653, + 1016 + ], + [ + 14.398, + 1024 + ], + [ + 16.248, + 1024 + ], + [ + 67.742, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 5, + "stress": false, + "first_ms": 4.605, + "total_ms": 62.473, + "tail_lag_ms": 57.806, + "batches": [ + [ + 4.605, + 8 + ], + [ + 4.648, + 1016 + ], + [ + 6.419, + 1024 + ], + [ + 8.283, + 1024 + ], + [ + 62.412, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 6, + "stress": false, + "first_ms": 12.603, + "total_ms": 62.607, + "tail_lag_ms": 49.944, + "batches": [ + [ + 12.603, + 8 + ], + [ + 12.646, + 1016 + ], + [ + 14.428, + 1024 + ], + [ + 16.266, + 1024 + ], + [ + 62.546, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 7, + "stress": false, + "first_ms": 9.609, + "total_ms": 58.052, + "tail_lag_ms": 48.375, + "batches": [ + [ + 9.609, + 8 + ], + [ + 9.639, + 1016 + ], + [ + 11.435, + 1024 + ], + [ + 13.336, + 1024 + ], + [ + 57.984, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 8, + "stress": false, + "first_ms": 11.405, + "total_ms": 60.414, + "tail_lag_ms": 48.939, + "batches": [ + [ + 11.405, + 8 + ], + [ + 11.449, + 1016 + ], + [ + 13.206, + 1024 + ], + [ + 15.074, + 1024 + ], + [ + 60.344, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 9, + "stress": false, + "first_ms": 10.363, + "total_ms": 54.497, + "tail_lag_ms": 44.072, + "batches": [ + [ + 10.363, + 8 + ], + [ + 10.389, + 1016 + ], + [ + 12.174, + 1024 + ], + [ + 14.064, + 1024 + ], + [ + 54.434, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 10, + "stress": false, + "first_ms": 4.345, + "total_ms": 58.396, + "tail_lag_ms": 53.992, + "batches": [ + [ + 4.345, + 8 + ], + [ + 4.379, + 1016 + ], + [ + 6.13, + 1024 + ], + [ + 7.978, + 1024 + ], + [ + 58.336, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 11, + "stress": false, + "first_ms": 5.627, + "total_ms": 52.461, + "tail_lag_ms": 46.694, + "batches": [ + [ + 5.627, + 8 + ], + [ + 5.684, + 1016 + ], + [ + 7.391, + 1024 + ], + [ + 9.276, + 1024 + ], + [ + 52.321, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 12, + "stress": false, + "first_ms": 12.856, + "total_ms": 63.633, + "tail_lag_ms": 50.697, + "batches": [ + [ + 12.856, + 8 + ], + [ + 12.893, + 1016 + ], + [ + 14.657, + 1024 + ], + [ + 16.519, + 1024 + ], + [ + 63.553, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 13, + "stress": false, + "first_ms": 8.911, + "total_ms": 61.815, + "tail_lag_ms": 52.841, + "batches": [ + [ + 8.911, + 8 + ], + [ + 8.949, + 1016 + ], + [ + 10.74, + 1024 + ], + [ + 12.609, + 1024 + ], + [ + 61.752, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 14, + "stress": false, + "first_ms": 6.569, + "total_ms": 60.941, + "tail_lag_ms": 54.301, + "batches": [ + [ + 6.569, + 8 + ], + [ + 6.609, + 1016 + ], + [ + 8.369, + 1024 + ], + [ + 10.213, + 1024 + ], + [ + 60.871, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 15, + "stress": false, + "first_ms": 5.077, + "total_ms": 60.978, + "tail_lag_ms": 55.83, + "batches": [ + [ + 5.077, + 8 + ], + [ + 5.111, + 1016 + ], + [ + 6.909, + 1024 + ], + [ + 8.787, + 1024 + ], + [ + 60.907, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 16, + "stress": false, + "first_ms": 3.948, + "total_ms": 56.629, + "tail_lag_ms": 52.62, + "batches": [ + [ + 3.948, + 8 + ], + [ + 3.971, + 1016 + ], + [ + 5.822, + 1024 + ], + [ + 7.622, + 1024 + ], + [ + 56.568, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 17, + "stress": false, + "first_ms": 7.023, + "total_ms": 60.519, + "tail_lag_ms": 53.424, + "batches": [ + [ + 7.023, + 8 + ], + [ + 7.075, + 1016 + ], + [ + 8.82, + 1024 + ], + [ + 10.728, + 1024 + ], + [ + 60.447, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 18, + "stress": false, + "first_ms": 5.961, + "total_ms": 50.962, + "tail_lag_ms": 44.932, + "batches": [ + [ + 5.961, + 8 + ], + [ + 5.999, + 1016 + ], + [ + 7.791, + 1024 + ], + [ + 9.661, + 1024 + ], + [ + 50.893, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 19, + "stress": false, + "first_ms": 3.714, + "total_ms": 50.807, + "tail_lag_ms": 47.025, + "batches": [ + [ + 3.714, + 8 + ], + [ + 3.748, + 1016 + ], + [ + 5.546, + 1024 + ], + [ + 7.388, + 1024 + ], + [ + 50.739, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 20, + "stress": false, + "first_ms": 12.326, + "total_ms": 65.002, + "tail_lag_ms": 52.605, + "batches": [ + [ + 12.326, + 8 + ], + [ + 12.37, + 1016 + ], + [ + 14.122, + 1024 + ], + [ + 16.033, + 1024 + ], + [ + 64.931, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 21, + "stress": false, + "first_ms": 6.654, + "total_ms": 61.648, + "tail_lag_ms": 54.924, + "batches": [ + [ + 6.654, + 8 + ], + [ + 6.681, + 1016 + ], + [ + 8.499, + 1024 + ], + [ + 10.28, + 1024 + ], + [ + 61.578, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 22, + "stress": false, + "first_ms": 4.528, + "total_ms": 53.306, + "tail_lag_ms": 48.706, + "batches": [ + [ + 4.528, + 8 + ], + [ + 4.561, + 1016 + ], + [ + 6.336, + 1024 + ], + [ + 8.202, + 1024 + ], + [ + 53.234, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 23, + "stress": false, + "first_ms": 10.71, + "total_ms": 62.962, + "tail_lag_ms": 52.173, + "batches": [ + [ + 10.71, + 8 + ], + [ + 10.753, + 1016 + ], + [ + 12.513, + 1024 + ], + [ + 14.404, + 1024 + ], + [ + 62.883, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 24, + "stress": false, + "first_ms": 7.231, + "total_ms": 54.233, + "tail_lag_ms": 46.918, + "batches": [ + [ + 7.231, + 8 + ], + [ + 7.267, + 1016 + ], + [ + 9.053, + 1024 + ], + [ + 10.907, + 1024 + ], + [ + 54.15, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 25, + "stress": false, + "first_ms": 12.521, + "total_ms": 67.816, + "tail_lag_ms": 55.221, + "batches": [ + [ + 12.521, + 8 + ], + [ + 12.563, + 1016 + ], + [ + 14.332, + 1024 + ], + [ + 16.192, + 1024 + ], + [ + 67.742, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 26, + "stress": false, + "first_ms": 4.15, + "total_ms": 54.434, + "tail_lag_ms": 50.206, + "batches": [ + [ + 4.15, + 8 + ], + [ + 4.188, + 1016 + ], + [ + 5.955, + 1024 + ], + [ + 7.831, + 1024 + ], + [ + 54.356, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 27, + "stress": false, + "first_ms": 9.533, + "total_ms": 67.823, + "tail_lag_ms": 58.217, + "batches": [ + [ + 9.533, + 8 + ], + [ + 9.573, + 1016 + ], + [ + 11.32, + 1024 + ], + [ + 13.162, + 1024 + ], + [ + 67.75, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 28, + "stress": false, + "first_ms": 12.166, + "total_ms": 61.44, + "tail_lag_ms": 49.201, + "batches": [ + [ + 12.166, + 8 + ], + [ + 12.207, + 1016 + ], + [ + 14.041, + 1024 + ], + [ + 15.885, + 1024 + ], + [ + 61.366, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 29, + "stress": false, + "first_ms": 10.532, + "total_ms": 69.58, + "tail_lag_ms": 58.978, + "batches": [ + [ + 10.532, + 8 + ], + [ + 10.572, + 1016 + ], + [ + 12.319, + 1024 + ], + [ + 14.182, + 1024 + ], + [ + 69.51, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 30, + "stress": false, + "first_ms": 11.519, + "total_ms": 67.66, + "tail_lag_ms": 56.064, + "batches": [ + [ + 11.519, + 8 + ], + [ + 11.57, + 1016 + ], + [ + 13.309, + 1024 + ], + [ + 15.163, + 1024 + ], + [ + 67.583, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 31, + "stress": false, + "first_ms": 3.709, + "total_ms": 53.068, + "tail_lag_ms": 49.276, + "batches": [ + [ + 3.709, + 8 + ], + [ + 3.738, + 1016 + ], + [ + 5.513, + 1024 + ], + [ + 7.391, + 1024 + ], + [ + 52.985, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 32, + "stress": false, + "first_ms": 10.192, + "total_ms": 69.371, + "tail_lag_ms": 59.114, + "batches": [ + [ + 10.192, + 8 + ], + [ + 10.234, + 1016 + ], + [ + 11.983, + 1024 + ], + [ + 13.862, + 1024 + ], + [ + 69.306, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 33, + "stress": false, + "first_ms": 11.587, + "total_ms": 68.228, + "tail_lag_ms": 56.565, + "batches": [ + [ + 11.587, + 8 + ], + [ + 11.628, + 1016 + ], + [ + 13.411, + 1024 + ], + [ + 15.259, + 1024 + ], + [ + 68.151, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 34, + "stress": false, + "first_ms": 3.226, + "total_ms": 53.61, + "tail_lag_ms": 50.31, + "batches": [ + [ + 3.226, + 8 + ], + [ + 3.263, + 1016 + ], + [ + 5.024, + 1024 + ], + [ + 6.895, + 1024 + ], + [ + 53.535, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 35, + "stress": false, + "first_ms": 9.08, + "total_ms": 53.883, + "tail_lag_ms": 44.728, + "batches": [ + [ + 9.08, + 8 + ], + [ + 9.121, + 1016 + ], + [ + 10.885, + 1024 + ], + [ + 12.754, + 1024 + ], + [ + 53.808, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 36, + "stress": false, + "first_ms": 3.966, + "total_ms": 53.642, + "tail_lag_ms": 49.606, + "batches": [ + [ + 3.966, + 8 + ], + [ + 4.002, + 1016 + ], + [ + 5.781, + 1024 + ], + [ + 7.652, + 1024 + ], + [ + 53.572, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 37, + "stress": false, + "first_ms": 9.647, + "total_ms": 54.407, + "tail_lag_ms": 44.701, + "batches": [ + [ + 9.647, + 8 + ], + [ + 9.679, + 1016 + ], + [ + 11.478, + 1024 + ], + [ + 13.319, + 1024 + ], + [ + 54.348, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 38, + "stress": false, + "first_ms": 3.897, + "total_ms": 53.538, + "tail_lag_ms": 49.573, + "batches": [ + [ + 3.897, + 8 + ], + [ + 3.937, + 1016 + ], + [ + 5.726, + 1024 + ], + [ + 7.594, + 1024 + ], + [ + 53.47, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 39, + "stress": false, + "first_ms": 9.942, + "total_ms": 63.038, + "tail_lag_ms": 52.986, + "batches": [ + [ + 9.942, + 8 + ], + [ + 9.989, + 1016 + ], + [ + 11.961, + 1024 + ], + [ + 13.59, + 1024 + ], + [ + 62.928, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 40, + "stress": false, + "first_ms": 6.702, + "total_ms": 53.39, + "tail_lag_ms": 46.62, + "batches": [ + [ + 6.702, + 8 + ], + [ + 6.742, + 1016 + ], + [ + 8.55, + 1024 + ], + [ + 10.406, + 1024 + ], + [ + 53.323, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 41, + "stress": false, + "first_ms": 12.759, + "total_ms": 68.997, + "tail_lag_ms": 56.165, + "batches": [ + [ + 12.759, + 8 + ], + [ + 12.805, + 1016 + ], + [ + 14.583, + 1024 + ], + [ + 16.444, + 1024 + ], + [ + 68.924, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 42, + "stress": false, + "first_ms": 14.212, + "total_ms": 67.552, + "tail_lag_ms": 53.18, + "batches": [ + [ + 14.212, + 8 + ], + [ + 14.252, + 1016 + ], + [ + 15.989, + 1024 + ], + [ + 17.86, + 1024 + ], + [ + 67.392, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 43, + "stress": false, + "first_ms": 6.457, + "total_ms": 56.341, + "tail_lag_ms": 49.807, + "batches": [ + [ + 6.457, + 8 + ], + [ + 6.5, + 1016 + ], + [ + 8.304, + 1024 + ], + [ + 10.141, + 1024 + ], + [ + 56.265, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 44, + "stress": false, + "first_ms": 9.89, + "total_ms": 68.566, + "tail_lag_ms": 58.596, + "batches": [ + [ + 9.89, + 8 + ], + [ + 9.932, + 1016 + ], + [ + 11.733, + 1024 + ], + [ + 13.551, + 1024 + ], + [ + 68.486, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 45, + "stress": false, + "first_ms": 12.195, + "total_ms": 68.563, + "tail_lag_ms": 56.299, + "batches": [ + [ + 12.195, + 8 + ], + [ + 12.252, + 1016 + ], + [ + 13.989, + 1024 + ], + [ + 15.842, + 1024 + ], + [ + 68.494, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 46, + "stress": false, + "first_ms": 3.475, + "total_ms": 62.087, + "tail_lag_ms": 58.54, + "batches": [ + [ + 3.475, + 8 + ], + [ + 3.497, + 1016 + ], + [ + 5.336, + 1024 + ], + [ + 7.126, + 1024 + ], + [ + 62.015, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 47, + "stress": false, + "first_ms": 12.21, + "total_ms": 58.181, + "tail_lag_ms": 45.895, + "batches": [ + [ + 12.21, + 8 + ], + [ + 12.248, + 1016 + ], + [ + 14.045, + 1024 + ], + [ + 15.882, + 1024 + ], + [ + 58.106, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 48, + "stress": false, + "first_ms": 13.808, + "total_ms": 64.092, + "tail_lag_ms": 50.215, + "batches": [ + [ + 13.808, + 8 + ], + [ + 13.85, + 1016 + ], + [ + 15.593, + 1024 + ], + [ + 17.495, + 1024 + ], + [ + 64.023, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 49, + "stress": false, + "first_ms": 9.319, + "total_ms": 64.968, + "tail_lag_ms": 55.573, + "batches": [ + [ + 9.319, + 8 + ], + [ + 9.364, + 1016 + ], + [ + 11.104, + 1024 + ], + [ + 12.943, + 1024 + ], + [ + 64.891, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + } + ] +} diff --git a/docs/测试说明/m3_data/m3_dev_stress_r200.json b/docs/测试说明/m3_data/m3_dev_stress_r200.json new file mode 100644 index 00000000..a8753793 --- /dev/null +++ b/docs/测试说明/m3_data/m3_dev_stress_r200.json @@ -0,0 +1,1616 @@ +{ + "mode": "remo", + "host": "192.168.1.100", + "port": 7003, + "ts_start": "2026-09-22 11:15:20", + "ts_end": "2026-09-22 11:15:29", + "duration_s": 9.36, + "samples": 45, + "cadence_ms": 100.0, + "tcp_nodelay": false, + "immediate_ack": null, + "in_band_ack_probe": false, + "stress_from": 15, + "connect_ms": 3.829, + "reconnect_ms": 19.634, + "reconnect_list_ms": [ + 19.634 + ], + "reconnect_stat": { + "n": 1, + "min_ms": 19.634, + "med_ms": 19.634, + "p95_ms": 19.634, + "max_ms": 19.634, + "spikes500": 0 + }, + "init": { + "rtt_ms": 4.027, + "geom": { + "w": 160, + "h": 160, + "framebytes": 3200, + "payload_len": 8 + } + }, + "cycle_all": { + "n": 45, + "min_ms": 52.89, + "med_ms": 62.956, + "p95_ms": 73.629, + "max_ms": 133.536, + "spikes500": 0 + }, + "cycle_quiet": { + "n": 15, + "min_ms": 52.89, + "med_ms": 59.901, + "p95_ms": 65.276, + "max_ms": 65.276, + "spikes500": 0 + }, + "cycle_stress": { + "n": 30, + "min_ms": 53.313, + "med_ms": 64.973, + "p95_ms": 73.877, + "max_ms": 133.536, + "spikes500": 0 + }, + "first_byte_all": { + "n": 45, + "min_ms": 4.941, + "med_ms": 11.404, + "p95_ms": 17.41, + "max_ms": 83.045, + "spikes500": 0 + }, + "tail_lag_all": { + "n": 45, + "min_ms": 43.569, + "med_ms": 50.182, + "p95_ms": 58.813, + "max_ms": 59.982, + "spikes500": 0 + }, + "crc": { + "ok": 45, + "fail": 0 + }, + "bitmap": { + "nontrivial_ok": 45, + "nontrivial_fail": 0 + }, + "frames": [ + { + "cycle": 0, + "stress": false, + "first_ms": 12.725, + "total_ms": 62.5, + "tail_lag_ms": 49.714, + "batches": [ + [ + 12.725, + 8 + ], + [ + 12.763, + 1016 + ], + [ + 14.39, + 1024 + ], + [ + 15.886, + 1024 + ], + [ + 62.438, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 1, + "stress": false, + "first_ms": 10.028, + "total_ms": 64.239, + "tail_lag_ms": 54.152, + "batches": [ + [ + 10.028, + 8 + ], + [ + 10.085, + 1016 + ], + [ + 11.331, + 1024 + ], + [ + 13.218, + 1024 + ], + [ + 64.181, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 2, + "stress": false, + "first_ms": 4.941, + "total_ms": 52.89, + "tail_lag_ms": 47.884, + "batches": [ + [ + 4.941, + 8 + ], + [ + 5.001, + 1016 + ], + [ + 6.73, + 1024 + ], + [ + 8.804, + 1024 + ], + [ + 52.825, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 3, + "stress": false, + "first_ms": 11.404, + "total_ms": 62.956, + "tail_lag_ms": 51.483, + "batches": [ + [ + 11.404, + 8 + ], + [ + 11.46, + 1016 + ], + [ + 13.208, + 1024 + ], + [ + 15.043, + 1024 + ], + [ + 62.888, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 4, + "stress": false, + "first_ms": 7.981, + "total_ms": 59.901, + "tail_lag_ms": 51.853, + "batches": [ + [ + 7.981, + 8 + ], + [ + 8.018, + 1016 + ], + [ + 9.841, + 1024 + ], + [ + 11.629, + 1024 + ], + [ + 59.834, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 5, + "stress": false, + "first_ms": 7.611, + "total_ms": 56.676, + "tail_lag_ms": 49.001, + "batches": [ + [ + 7.611, + 8 + ], + [ + 7.653, + 1016 + ], + [ + 9.43, + 1024 + ], + [ + 11.283, + 1024 + ], + [ + 56.611, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 6, + "stress": false, + "first_ms": 10.582, + "total_ms": 56.803, + "tail_lag_ms": 46.155, + "batches": [ + [ + 10.582, + 8 + ], + [ + 10.633, + 1016 + ], + [ + 12.416, + 1024 + ], + [ + 14.274, + 1024 + ], + [ + 56.736, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 7, + "stress": false, + "first_ms": 10.365, + "total_ms": 57.556, + "tail_lag_ms": 47.104, + "batches": [ + [ + 10.365, + 8 + ], + [ + 10.398, + 1016 + ], + [ + 12.174, + 1024 + ], + [ + 14.041, + 1024 + ], + [ + 57.468, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 8, + "stress": false, + "first_ms": 12.598, + "total_ms": 62.908, + "tail_lag_ms": 50.182, + "batches": [ + [ + 12.598, + 8 + ], + [ + 12.638, + 1016 + ], + [ + 14.401, + 1024 + ], + [ + 16.211, + 1024 + ], + [ + 62.781, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 9, + "stress": false, + "first_ms": 9.463, + "total_ms": 58.34, + "tail_lag_ms": 48.803, + "batches": [ + [ + 9.463, + 8 + ], + [ + 9.494, + 1016 + ], + [ + 11.328, + 1024 + ], + [ + 13.157, + 1024 + ], + [ + 58.266, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 10, + "stress": false, + "first_ms": 10.832, + "total_ms": 60.588, + "tail_lag_ms": 49.69, + "batches": [ + [ + 10.832, + 8 + ], + [ + 10.879, + 1016 + ], + [ + 12.642, + 1024 + ], + [ + 14.475, + 1024 + ], + [ + 60.522, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 11, + "stress": false, + "first_ms": 9.625, + "total_ms": 53.264, + "tail_lag_ms": 43.569, + "batches": [ + [ + 9.625, + 8 + ], + [ + 9.658, + 1016 + ], + [ + 11.44, + 1024 + ], + [ + 13.321, + 1024 + ], + [ + 53.195, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 12, + "stress": false, + "first_ms": 5.153, + "total_ms": 55.968, + "tail_lag_ms": 50.743, + "batches": [ + [ + 5.153, + 8 + ], + [ + 5.2, + 1016 + ], + [ + 7.015, + 1024 + ], + [ + 8.806, + 1024 + ], + [ + 55.896, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 13, + "stress": false, + "first_ms": 9.061, + "total_ms": 65.276, + "tail_lag_ms": 56.153, + "batches": [ + [ + 9.061, + 8 + ], + [ + 9.098, + 1016 + ], + [ + 10.865, + 1024 + ], + [ + 12.744, + 1024 + ], + [ + 65.214, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 14, + "stress": false, + "first_ms": 11.328, + "total_ms": 65.241, + "tail_lag_ms": 53.843, + "batches": [ + [ + 11.328, + 8 + ], + [ + 11.384, + 1016 + ], + [ + 13.145, + 1024 + ], + [ + 14.973, + 1024 + ], + [ + 65.171, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 15, + "stress": true, + "first_ms": 18.374, + "total_ms": 65.022, + "tail_lag_ms": 46.581, + "batches": [ + [ + 18.374, + 8 + ], + [ + 18.413, + 1016 + ], + [ + 20.168, + 1024 + ], + [ + 22.108, + 1024 + ], + [ + 64.955, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 16, + "stress": true, + "first_ms": 12.718, + "total_ms": 67.532, + "tail_lag_ms": 54.737, + "batches": [ + [ + 12.718, + 8 + ], + [ + 12.754, + 1016 + ], + [ + 14.521, + 1024 + ], + [ + 16.343, + 1024 + ], + [ + 67.456, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 17, + "stress": true, + "first_ms": 16.515, + "total_ms": 65.276, + "tail_lag_ms": 48.682, + "batches": [ + [ + 16.515, + 8 + ], + [ + 16.575, + 1016 + ], + [ + 18.538, + 1024 + ], + [ + 20.167, + 1024 + ], + [ + 65.197, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 18, + "stress": true, + "first_ms": 10.352, + "total_ms": 60.735, + "tail_lag_ms": 50.31, + "batches": [ + [ + 10.352, + 8 + ], + [ + 10.401, + 1016 + ], + [ + 12.257, + 1024 + ], + [ + 14.073, + 1024 + ], + [ + 60.662, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 19, + "stress": true, + "first_ms": 14.992, + "total_ms": 64.973, + "tail_lag_ms": 49.912, + "batches": [ + [ + 14.992, + 8 + ], + [ + 15.028, + 1016 + ], + [ + 16.791, + 1024 + ], + [ + 18.653, + 1024 + ], + [ + 64.904, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 20, + "stress": true, + "first_ms": 83.045, + "total_ms": 133.536, + "tail_lag_ms": 50.409, + "batches": [ + [ + 83.045, + 8 + ], + [ + 83.079, + 1016 + ], + [ + 84.706, + 1024 + ], + [ + 86.822, + 1024 + ], + [ + 133.455, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 21, + "stress": true, + "first_ms": 9.003, + "total_ms": 55.661, + "tail_lag_ms": 46.585, + "batches": [ + [ + 9.003, + 8 + ], + [ + 9.037, + 1016 + ], + [ + 10.726, + 1024 + ], + [ + 12.676, + 1024 + ], + [ + 55.588, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 22, + "stress": true, + "first_ms": 12.838, + "total_ms": 59.933, + "tail_lag_ms": 47.012, + "batches": [ + [ + 12.838, + 8 + ], + [ + 12.887, + 1016 + ], + [ + 14.534, + 1024 + ], + [ + 16.375, + 1024 + ], + [ + 59.85, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 23, + "stress": true, + "first_ms": 12.267, + "total_ms": 71.152, + "tail_lag_ms": 58.813, + "batches": [ + [ + 12.267, + 8 + ], + [ + 12.297, + 1016 + ], + [ + 14.119, + 1024 + ], + [ + 15.94, + 1024 + ], + [ + 71.08, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 24, + "stress": true, + "first_ms": 12.781, + "total_ms": 64.794, + "tail_lag_ms": 51.942, + "batches": [ + [ + 12.781, + 8 + ], + [ + 12.822, + 1016 + ], + [ + 14.649, + 1024 + ], + [ + 16.579, + 1024 + ], + [ + 64.723, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 25, + "stress": true, + "first_ms": 7.789, + "total_ms": 55.069, + "tail_lag_ms": 47.212, + "batches": [ + [ + 7.789, + 8 + ], + [ + 7.823, + 1016 + ], + [ + 9.574, + 1024 + ], + [ + 11.505, + 1024 + ], + [ + 55.002, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 26, + "stress": true, + "first_ms": 12.287, + "total_ms": 63.943, + "tail_lag_ms": 51.575, + "batches": [ + [ + 12.287, + 8 + ], + [ + 12.324, + 1016 + ], + [ + 14.203, + 1024 + ], + [ + 16.027, + 1024 + ], + [ + 63.862, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 27, + "stress": true, + "first_ms": 9.024, + "total_ms": 53.313, + "tail_lag_ms": 44.219, + "batches": [ + [ + 9.024, + 8 + ], + [ + 9.056, + 1016 + ], + [ + 10.854, + 1024 + ], + [ + 12.674, + 1024 + ], + [ + 53.243, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 28, + "stress": true, + "first_ms": 15.279, + "total_ms": 64.864, + "tail_lag_ms": 49.513, + "batches": [ + [ + 15.279, + 8 + ], + [ + 15.326, + 1016 + ], + [ + 17.083, + 1024 + ], + [ + 18.948, + 1024 + ], + [ + 64.792, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 29, + "stress": true, + "first_ms": 9.903, + "total_ms": 57.154, + "tail_lag_ms": 47.175, + "batches": [ + [ + 9.903, + 8 + ], + [ + 9.944, + 1016 + ], + [ + 11.697, + 1024 + ], + [ + 13.56, + 1024 + ], + [ + 57.078, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 30, + "stress": true, + "first_ms": 12.547, + "total_ms": 66.518, + "tail_lag_ms": 53.909, + "batches": [ + [ + 12.547, + 8 + ], + [ + 12.596, + 1016 + ], + [ + 14.309, + 1024 + ], + [ + 16.188, + 1024 + ], + [ + 66.457, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 31, + "stress": true, + "first_ms": 17.41, + "total_ms": 62.968, + "tail_lag_ms": 45.481, + "batches": [ + [ + 17.41, + 8 + ], + [ + 17.45, + 1016 + ], + [ + 19.323, + 1024 + ], + [ + 21.11, + 1024 + ], + [ + 62.892, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 32, + "stress": true, + "first_ms": 14.245, + "total_ms": 72.066, + "tail_lag_ms": 57.738, + "batches": [ + [ + 14.245, + 8 + ], + [ + 14.28, + 1016 + ], + [ + 16.12, + 1024 + ], + [ + 17.888, + 1024 + ], + [ + 71.982, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 33, + "stress": true, + "first_ms": 14.611, + "total_ms": 61.311, + "tail_lag_ms": 46.626, + "batches": [ + [ + 14.611, + 8 + ], + [ + 14.645, + 1016 + ], + [ + 16.383, + 1024 + ], + [ + 18.239, + 1024 + ], + [ + 61.237, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 34, + "stress": true, + "first_ms": 12.675, + "total_ms": 71.81, + "tail_lag_ms": 59.064, + "batches": [ + [ + 12.675, + 8 + ], + [ + 12.704, + 1016 + ], + [ + 14.626, + 1024 + ], + [ + 16.408, + 1024 + ], + [ + 71.74, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 35, + "stress": true, + "first_ms": 12.367, + "total_ms": 67.029, + "tail_lag_ms": 54.589, + "batches": [ + [ + 12.367, + 8 + ], + [ + 12.408, + 1016 + ], + [ + 14.201, + 1024 + ], + [ + 16.068, + 1024 + ], + [ + 66.956, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 36, + "stress": true, + "first_ms": 10.935, + "total_ms": 65.452, + "tail_lag_ms": 54.444, + "batches": [ + [ + 10.935, + 8 + ], + [ + 10.977, + 1016 + ], + [ + 12.779, + 1024 + ], + [ + 14.471, + 1024 + ], + [ + 65.379, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 37, + "stress": true, + "first_ms": 17.025, + "total_ms": 73.629, + "tail_lag_ms": 56.521, + "batches": [ + [ + 17.025, + 8 + ], + [ + 17.061, + 1016 + ], + [ + 18.882, + 1024 + ], + [ + 20.694, + 1024 + ], + [ + 73.547, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 38, + "stress": true, + "first_ms": 15.293, + "total_ms": 73.877, + "tail_lag_ms": 58.392, + "batches": [ + [ + 15.293, + 8 + ], + [ + 15.338, + 1016 + ], + [ + 16.99, + 1024 + ], + [ + 18.939, + 1024 + ], + [ + 73.685, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 39, + "stress": true, + "first_ms": 12.884, + "total_ms": 62.116, + "tail_lag_ms": 49.158, + "batches": [ + [ + 12.884, + 8 + ], + [ + 12.95, + 1016 + ], + [ + 14.649, + 1024 + ], + [ + 16.51, + 1024 + ], + [ + 62.042, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 40, + "stress": true, + "first_ms": 10.286, + "total_ms": 61.969, + "tail_lag_ms": 51.612, + "batches": [ + [ + 10.286, + 8 + ], + [ + 10.322, + 1016 + ], + [ + 12.03, + 1024 + ], + [ + 13.912, + 1024 + ], + [ + 61.898, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 41, + "stress": true, + "first_ms": 7.578, + "total_ms": 55.043, + "tail_lag_ms": 47.389, + "batches": [ + [ + 7.578, + 8 + ], + [ + 7.605, + 1016 + ], + [ + 9.375, + 1024 + ], + [ + 11.218, + 1024 + ], + [ + 54.968, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 42, + "stress": true, + "first_ms": 12.287, + "total_ms": 61.958, + "tail_lag_ms": 49.603, + "batches": [ + [ + 12.287, + 8 + ], + [ + 12.312, + 1016 + ], + [ + 14.221, + 1024 + ], + [ + 15.983, + 1024 + ], + [ + 61.89, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 43, + "stress": true, + "first_ms": 9.986, + "total_ms": 66.879, + "tail_lag_ms": 56.811, + "batches": [ + [ + 9.986, + 8 + ], + [ + 10.024, + 1016 + ], + [ + 11.804, + 1024 + ], + [ + 13.686, + 1024 + ], + [ + 66.797, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + }, + { + "cycle": 44, + "stress": true, + "first_ms": 8.66, + "total_ms": 68.709, + "tail_lag_ms": 59.982, + "batches": [ + [ + 8.66, + 8 + ], + [ + 8.707, + 1016 + ], + [ + 10.432, + 1024 + ], + [ + 12.325, + 1024 + ], + [ + 68.642, + 137 + ] + ], + "bytes": 3209, + "tag": 187, + "cmd": 3, + "crc_ok": true, + "nontrivial": true + } + ] +} diff --git a/docs/测试说明/链路延迟测试说明.md b/docs/测试说明/链路延迟测试说明.md index 457ddd4b..aebae08a 100644 --- a/docs/测试说明/链路延迟测试说明.md +++ b/docs/测试说明/链路延迟测试说明.md @@ -6,6 +6,7 @@ > **数据日期**:2026-09-22 台架(COM6 @115200;STM32F407ZGTx @168MHz + CH395F,SPI2 分频 8) > **数据文件**:`m2_data/`、`m3_data/`(JSON + 串口证据片段);本文所有数字均可回溯到这些文件 > **代码状态**:D10 / E-02 / D17 / D12 / D14 / D15 / D16 已修复并台架复验(§8); +> D1(重传周期 200ms)/ D6(per-recv 日志)2026-09-22 已实施并台架复验(P0-a/P0-b,§10.1); > D20(开机首个 FTP 会话第 2 个数据连接 425)已定位未修(§8.2) > **合并说明**:本文统一原《链路延迟测试说明》《链路时延实测数据分析》《远程显示延迟分析》 > (2026-09-22);过程性历史记录(逐日变更、调试过程)不再保留,现状以本文与 git 历史为准。 @@ -14,9 +15,10 @@ ## 1. 一句话结论(当前状态) -**远端显示一帧(3209B 全帧)端到端实测中位 66.0ms,其中约 52.6ms(79%)是帧尾那 137B 小段的等待**; -MCU 侧真实处理只占 7.1ms,任务拾取/调度约 6.8ms。同一客户端、同一台 PC 打 PC 模拟器只要 6.8ms -(Δ = 59.2ms 为 CH395F 链路净贡献,且模拟器完全没有尾批延迟)。 +**远端显示一帧(3209B 全帧)端到端实测中位 61.6ms,其中约 52.6ms(85%)是帧尾那 137B 小段的等待**; +MCU 侧真实处理只占 6.7ms,任务拾取/调度约 2.3ms(2026-09-22 重锁:P0-b 删 per-recv 日志后 +帧周期 66.0→61.6ms,拾取/调度 6.8→2.3ms,差的 ~4.4ms 即原 per-recv 日志税)。同一客户端、同一台 PC 打 PC 模拟器只要 6.8ms +(Δ = 54.8ms 为 CH395F 链路净贡献,且模拟器完全没有尾批延迟)。 - **尾批根因(已确证,无需抓包)**:芯片按 Nagle 扣住帧尾的次 MSS 段(MSS=1024,3209 = 3×1024 + 137) 等对端 ACK,Windows 延迟 ACK 把这一等推迟 ~50ms(§7.3 五组带内实验)。 @@ -24,7 +26,8 @@ MCU 侧真实处理只占 7.1ms,任务拾取/调度约 6.8ms。同一客户端 非 Windows 用"入站轻推"兜底(**29.4ms**,2.3×);协议与固件都不需要改(§7.4)。 - **设备侧无可行解**(帧长 3209 为质数、TX FIFO = MSS、CH395F 无 Nagle 开关)→ 不必再投入。 - **缺陷**:D10(断线重监听 588ms 冻结 netTask)、E-02(一条空闲 FTP 控制连接冻结全网 17.7s)、 - D17(INIT 应答帧字节数字段恒 0)等已量化并**修复 + 台架复验**(§8.1);D20 已定位未修(§8.2)。 + D17(INIT 应答帧字节数字段恒 0)等已量化并**修复 + 台架复验**(§8.1); + D1(重传周期 500→200ms)/ D6(per-recv 日志)2026-09-22 已实施(§10.1);D20 已定位未修(§8.2)。 --- @@ -68,7 +71,7 @@ sequenceDiagram N->>C: WRITE_SEND_BUF ≤1KB(SPI DMA ≈1.6ms/KB) C-->>N: SENBUF_FREE 中断 end - Note over C: D1 丢一段 → 重传 +500ms(现 8×500ms;D7 供包) + Note over C: D1 丢一段 → 重传 +200ms(现 8×200ms,P0-a 已实装;D7 供包) C-->>F: 3×1024B 满段 + 137B 尾段 Note over F: D4 Windows 延迟确认 40~200ms(生产客户端已关)→ 尾段扣住 ~50ms F->>B: PNG → base64 → socketio → canvas @@ -85,7 +88,7 @@ sequenceDiagram | `NET_SEND_CHUNK_MAX` | **1KB**(受发送缓冲与 DMA 载荷 2048 双重钳制) | `net_socket.c` | | LCDMEM 一帧分块数 / 分段数 | **4**(1024×3 + 137) | 3209 ÷ 1024 | | CH395F 内部 RAM | 48 块 × 512B = 24KB,`net_init` 按 8 socket 均分 6 块 | `net_init` | -| TCP 重传 | **8 次 × 500ms = 4s 窗口**(固定周期,非 RTT 自适应) | `ch395f_set_retrans_count/period` | +| TCP 重传 | **8 次 × 200ms = 1.6s 窗口**(固定周期,非 RTT 自适应;P0-a 2026-09-22 实装,原 8×500ms=4s) | `NET_RETRANS_COUNT/PERIOD_MS`(`net_config.h`) | | SPI2 速率 | APB1 42MHz ÷ 8 ≈ **5.25 Mbit/s** → 1KB ≈ **1.6ms**(分频 8 为 PCB 约束,勿"优化") | `Src/spi.c` | | 发送等待超时 | 1s(`NET_SEND_TIMEOUT_MS`) | `net_config.h` | | 接收超时 | 30s(`NET_RECV_TIMEOUT_MS`) | `net_config.h` | @@ -110,15 +113,15 @@ sequenceDiagram | **L1** | SPI 字节命令 | 一条小 SPI 事务(GET_IC_VER / CHECK_EXIST / GLOB_INT,4~7B)端到端 | MCU,DWT µs,Phase 12,N=100/命令 | 10 / 15 / 15µs | SPI 走线/PCB/分频/DMA 配置 | | **L2** | SPI DMA | `ch395f_read_recv_buf(N)` 完整 DMA 事务(含 CS 切换),N ∈ {4, 64, 1024, 2048} | MCU,DWT µs,Phase 12,N=100/档 | 20 / 114 / **1611** / 3208µs(斜率 1.56µs/B + 固定 14µs) | SPI2/DMA/总线异常 | | **L3** | 发送分块握手 | `write_send_buf(1KB)` → `SENBUF_FREE` 的等待时长(= `net_send_locked` 每 chunk 的真实等待) | MCU(netTask 上下文),Phase 13 | **219µs**/chunk | 芯片发送路径 / 重传(D1) / 链路(D7) | -| **L4** | 芯片→线上+PC | 数据交入芯片协议栈 → PC 首见字节 / 收齐全帧(peer 逐 `recv()` 批次打时间戳) | PC(peer),Phase 13/14 | 首批 8.6ms;**段间间隙 ≥500ms = 重传** | D1/D4/D7("网络延迟"直接证据) | -| **L5** | 队列往返 | 调用方视角 `net_recv(DONTWAIT)` / `net_send` 全程 = 入队 + netTask 调度 + 处理 + 通知 | MCU(调用方计时),Phase 13,**两档**:静默基线 + 压力档(并发 FTP 流量) | 静默:收 5997µs / 发 987µs | D3(E-02 头阻塞,已修) / D5 调度 | -| **L6** | 请求→首字节 | peer 发 10B 请求 → MCU 收齐并回显(服务端视角);与 PC 侧对照,差值 = 线路 + PC 栈 | MCU + PC 双侧,Phase 13 | MCU 319µs / PC 1.4ms | MCU 收路径/调度 | +| **L4** | 芯片→线上+PC | 数据交入芯片协议栈 → PC 首见字节 / 收齐全帧(peer 逐 `recv()` 批次打时间戳) | PC(peer),Phase 13/14 | 首批 8.6ms;**段间间隙 ≥200ms = 重传**(P0-a 后粒度;旧固件 500ms) | D1/D4/D7("网络延迟"直接证据) | +| **L5** | 队列往返 | 调用方视角 `net_recv(DONTWAIT)` / `net_send` 全程 = 入队 + netTask 调度 + 处理 + 通知 | MCU(调用方计时),Phase 13,**两档**:静默基线 + 压力档(并发 FTP 流量) | 静默:收 1223µs / 发 988µs(2026-09-22 重锁,P0-b 后) | D3(E-02 头阻塞,已修) / D5 调度 | +| **L6** | 请求→首字节 | peer 发 10B 请求 → MCU 收齐并回显(服务端视角);与 PC 侧对照,差值 = 线路 + PC 栈 | MCU + PC 双侧,Phase 13 | MCU 986µs / PC 3.9ms | MCU 收路径/调度 | | **L7** | 整帧 3209B 往返 | LCDMEM 全帧:PC 发 → 收齐(含 L3+L4) | PC 为主,Phase 13 | 61.0ms(M2);**spike(≥500ms)=0** | D1+D2+D4 综合 | -| **L8** | 生产路径帧周期 | **真实 uiTask + 真实 `ui_net_sink`**(:7003)完整帧周期:请求拾取(10ms 拍)+ 队列 + 发送 + L4 + peer 侧编码 | MCU 探针 + PC,Phase 14 | 真机 66.0ms / 模拟器 6.8ms(含 peer 100ms 节拍) | 全段(用户真实体感) | +| **L8** | 生产路径帧周期 | **真实 uiTask + 真实 `ui_net_sink`**(:7003)完整帧周期:请求拾取(10ms 拍)+ 队列 + 发送 + L4 + peer 侧编码 | MCU 探针 + PC,Phase 14 | 真机 61.6ms / 模拟器 6.8ms(含 peer 100ms 节拍) | 全段(用户真实体感) | | **L9** | 连接/重监听 | connect→ESTABLISHED;close→relisten 成功 | MCU(net_poll 观测点),Phase 14 | relisten **89ms**(D10 修复后) | 握手/队列;**≥500ms = D10 回归** | -| **L10** | 日志税 | 一行 60 字符 `printf`(现 fputc 逐字节 @115200)耗时 | MCU,Phase 13 附带 | **4396µs/行** | D6(待办 P0-b/S8) | +| **L10** | 日志税 | 一行 60 字符 `printf`(现 fputc 逐字节 @115200)耗时 | MCU,Phase 13 附带 | **4402µs/行** | D6(per-recv 日志已删 2026-09-22;S8 非阻塞日志仍待办) | | **L11** | uiTask 节拍 | 生产循环实测周期(`osDelay(10)` 之外多花多少 = LVGL 渲染 + 渲染中排空) | MCU 探针,Phase 14 | **10986µs**(渲染仅 ~1ms/帧) | D5/D9(实测均非瓶颈) | -| **Δ** | CH395F 净贡献 | `L8(真机) − L8(模拟器)`,同一 peer 交替跑 | PC,Phase 14 | **59.2ms**(阈值 ≤80ms) | 直接回答"网络延迟"占多少 | +| **Δ** | CH395F 净贡献 | `L8(真机) − L8(模拟器)`,同一 peer 交替跑 | PC,Phase 14 | **54.8ms**(阈值 ≤80ms) | 直接回答"网络延迟"占多少 | --- @@ -333,70 +336,83 @@ DMA 斜率实测 1.56µs/B(≈5.25 Mbit/s,与 SPI2 分频 8 @42MHz APB1 设 ### 6.2 M2 段(Phase 13,芯片 + 队列) -run12/run13/run15 三次独立完整 PASS(6 段全 OK、零尖峰、`1/1 PASSED`、peer exit 0); -下表 = run15(最终代码)基线。 +2026-09-22 重锁(P0-a/P0-b):同日 A/B 两档对照——**B1**(周期 500ms + per-recv 日志,= run15 条件, +复跑数值与 run15 基线重合 ±0.2%)→ **B2**(周期 200ms + per-recv 日志已删,= 当前代码)。 +两档全部 `1/1 PASSED`、零尖峰、peer exit 0;下表 = **B2 基线**(A/B 差值即 P0-b 效果,P0-a 在干净链路上惰性)。 **MCU 侧(`[LAT]` 报告,安静档 `ftp_stress=0`)** | 段(seg) | 测量含义 | med(min/max, n) | warn(med >) | crit(med >) | |---|---|---|---|---| -| `queue_rt_recv` | L5 对端灌 100B×20@50ms,MCU 非阻塞收的队列往返 | **5997µs**(5513/6033, 20) | 10ms | 100ms | -| `queue_rt_send` | L5 MCU 阻塞发 100B×20 | **987µs**(838/1209, 20) | 10ms | 100ms | -| `chunk_wait` | L3 16×4KB,芯片 chunk 内 SENBUF 等待(探针) | **219µs**(214/381, 64) | 10ms | 500ms(spike) | -| `logtax_line` | 60 字符 printf @115200(本地) | **4396µs**(4394/4422, 10) | 10ms | 25ms | -| `req2first_mcu` | L6 10B 请求到齐 → 回显发出 | **319µs**(308/338, 10) | 20ms | 200ms | -| `fullframe_mcu` | L7 9B 请求 → 3209B 全帧发给芯片(netTask 内 4 分块) | **6028µs**(5991/6066, 10) | 50ms | 500ms | +| `queue_rt_recv` | L5 对端灌 100B×20@50ms,MCU 非阻塞收的队列往返 | **1223µs**(1194/1223, 20) | 10ms | 100ms | +| `queue_rt_send` | L5 MCU 阻塞发 100B×20 | **988µs**(840/1216, 20) | 10ms | 100ms | +| `chunk_wait` | L3 16×4KB,芯片 chunk 内 SENBUF 等待(探针) | **219µs**(213/378, 64) | 10ms | 500ms(spike) | +| `logtax_line` | 60 字符 printf @115200(本地) | **4402µs**(4396/8779, 10) | 10ms | 25ms | +| `req2first_mcu` | L6 10B 请求到齐 → 回显发出 | **986µs**(979/1015, 10) | 20ms | 200ms | +| `fullframe_mcu` | L7 9B 请求 → 3209B 全帧发给芯片(netTask 内 4 分块) | **6614µs**(6546/6649, 10) | 50ms | 500ms | + +(旧 run15 值对照:`queue_rt_recv` 5997 / `req2first_mcu` 319 / `fullframe_mcu` 6028µs——前两项差异均为 +per-recv 日志移除的调度效应,非芯片行为变化:`queue_rt_recv` 差值 4.8ms ≈ 一行日志税;`req2first_mcu` +旧值 319µs 是日志阻塞期 netTask 恰在循环内(同轮命中)的幸运快值,新值 ≈ 1 个 netTask 循环周期(~1ms), +是隔离小帧发送的真实成本。`queue_rt_send`/`chunk_wait` 两档同值 = 与日志无关的段。) **PC 侧端到端(peer JSON,含线路 + Windows 栈)** | 段 | med(min/max) | 说明 | |---|---|---| -| L6 端到端(op→收到回显) | 8.9ms(6.3/16.0) | 比 MCU 侧 `req2first_mcu` 多 ~7ms → PC/线路段 | -| L7 首字节 | 11.3ms(7.8/16.5) | 同上量级 | -| L7 全帧 3209B | 57.9ms(52.6/72.3) | 每帧固定 4 个 recv 批次;**尾批 137B 稳定迟到 ~50ms**(§7.3) | +| L6 端到端(op→收到回显) | 3.9ms(1.7/12.0) | 比 MCU 侧 `req2first_mcu` 多 ~2.9ms → PC/线路段 | +| L7 首字节 | 10.0ms(4.0/13.8) | 同上量级 | +| L7 全帧 3209B | 57.9ms(53.6/69.9) | 每帧固定 4 个 recv 批次;**尾批 137B 稳定迟到 ~50ms**(§7.3) | | L7 CRC 校验 | 10/0 fail | 帧格式/CRC 正确(生产格式对齐后) | -| L3 flood 64KB(16×4KB) | 7.5~8.7ms/次 | ≈2ms/KB,满块无尾批惩罚 | +| L3 flood 64KB(16×4KB) | 7.5~8.7ms/次 | ≈2ms/KB,满块无尾批惩罚(MCU 发送路径,与 per-recv 日志无关) | **M2 三个结论**: -1. **安静档不存在 500ms 台阶**——六段全部 `verdict=OK`、零尖峰、p95≈med;会话级路径的 MCU 净成本 - 量级 ~6ms(`queue_rt_recv`),与 netTask 轮询节拍同量级; +1. **安静档不存在重传台阶**——六段全部 `verdict=OK`、零尖峰、p95≈med;会话级路径的 MCU 净成本 + ~1.2ms(`queue_rt_recv`,P0-b 删日志后;旧值 5.997ms 含 per-recv 日志税 4.4ms/行); 2. **芯片 chunk 级不是瓶颈**——`chunk_wait` ≈219µs ≈ 每 chunk SPI 成本(1.61ms)的 1/7, `SENBUF_FREE` 等待远小于 SPI 搬运本身; -3. **L7 全帧的最后 137B 尾巴稳定迟到 ~50ms**(10/10 帧)——尾批主导整帧时长,MCU 侧发完 3209B 仅 6.0ms +3. **L7 全帧的最后 137B 尾巴稳定迟到 ~50ms**(10/10 帧)——尾批主导整帧时长,MCU 侧发完 3209B 仅 6.6ms → 延迟不在 MCU 发送路径,在芯片 TCP 尾段发送/对端 ACK 交互(M3 定性见 §7.3)。 ### 6.3 M3 段(Phase 14,生产路径 + 模拟器 Δ) -**MCU 侧(`[LAT]` 报告,真实 uiTask + `ui_net_sink` :7003;修复后代码)** +**MCU 侧(`[LAT]` 报告,真实 uiTask + `ui_net_sink` :7003;P0-a/P0-b 代码,2026-09-22 重锁)** | 段(seg) | 测量含义 | 实测 med(min/max, n) | warn(med >) | crit(med >) | |---|---|---|---|---| -| `ui_loop`(L11) | uiTask 生产循环实测周期(渲染+轮询+osDelay(10)) | **10986µs**(10970/21000, 120) | 25ms | 50ms | -| `prod_cycle_mcu`(L8) | LCDMEM 取 1bpp + 组帧 + net_send 4 分块(不含 10ms 拾取拍) | **7142µs**(7111/7179, 50) | 20ms | 200ms | +| `ui_loop`(L11) | uiTask 生产循环实测周期(渲染+轮询+osDelay(10)) | **10986µs**(10951/11022, 120) | 25ms | 50ms | +| `prod_cycle_mcu`(L8) | LCDMEM 取 1bpp + 组帧 + net_send 4 分块(不含 10ms 拾取拍) | **6707µs**(6701/6757, 50) | 20ms | 200ms | | `relisten`(L9) | 断线后 auto-relisten 全程(**修复后**:单次尝试 + netTask 延迟重试) | **89000µs ×3**(三次同值) | 100ms | 500ms | +(旧值对照:`prod_cycle_mcu` 7142µs → 6707µs = P0-b 移除请求路径 per-recv 日志的 ~435µs; +`ui_loop`/`relisten` 两档同值 = 与日志无关的段。) + `relisten` 阈值说明:修复前 588000µs(Trap 09 `osDelay(500)` 忙等)→ crit 500ms 即 D10 指纹; D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故 warn 放宽到 **100ms**、crit 保持 500ms (仍能捕获"退回阻塞重试"的回归)。 **PC 侧端到端(peer `--mode remo`,与模拟器 A/B)** -| 指标 | 真机(65 帧) | 模拟器(50 帧) | Δ(真机−模拟器) | 阈值 | +| 指标 | 真机(50 帧静默档) | 模拟器(50 帧) | Δ(真机−模拟器) | 阈值 | |---|---|---|---|---| -| 帧周期 total | **66.0ms**(53.3/75.3) | **6.8ms**(0.6/13.1) | **+59.2ms** | ≤80ms | -| 首字节 | 13.9ms(8.5/19.1) | 6.7ms(0.5/13.0) | +7.2ms | — | -| **尾批延迟 tail lag** | **52.6ms**(43.3/61.5) | **0.0ms**(0/0.1) | **+52.6ms** | — | -| 帧 CRC / 位图非平凡 | 65/0、65/65 | 50/0、50/50 | — | 全通过 | -| 连接 / 断开重连(+INIT) | 2.6ms / 23.5~34.7ms | 10.5ms / 32.0ms | — | ≤150ms | +| 帧周期 total | **61.6ms**(50.4/69.8) | **6.8ms**(0.6/13.1) | **+54.8ms** | ≤80ms | +| 首字节 | 9.6ms(3.2/14.2) | 6.7ms(0.5/13.0) | +2.9ms | — | +| **尾批延迟 tail lag** | **52.6ms**(44.1/59.1) | **0.0ms**(0/0.1) | **+52.6ms** | — | +| 帧 CRC / 位图非平凡 | 50/0、50/50 | 50/0、50/50 | — | 全通过 | +| 连接 / 断开重连(+INIT) | 17.1ms / 22.4ms | 10.5ms / 32.0ms | — | ≤150ms | + +(模拟器列为 2026-09-21 基线,模拟器工程本日未改动;真机列 = 2026-09-22 P0-a/P0-b 代码重测。 +旧真机值:帧周期 66.0ms / 首字节 13.9ms / 重连 23.5~34.7ms。) **压力档(`--ftp-stress`,E-02 复现;第 15 帧起 FTP 停留半登录态)** | 分桶 | n | med | p95 | max | 尖峰(≥500ms) | |---|---|---|---|---|---| -| quiet(0~14 帧) | 15 | 65.9ms | 75.8ms | 75.8ms | 0 | -| stress(15~44 帧,**E-02 修复后**) | 30 | **74.7ms** | 90.8ms | **106.8ms** | **0** | +| quiet(0~14 帧) | 15 | 59.9ms | 65.3ms | 65.3ms | 0 | +| stress(15~44 帧,**E-02 修复后 + P0-a/P0-b**) | 30 | **65.0ms** | 73.9ms | **133.5ms** | **0** | -(E-02 修复前 stress 档 med 17718ms、尖峰 1 次 = 17.7s 全网冻结;修复后零尖峰,见 §8.1。) +(E-02 修复前 stress 档 med 17718ms、尖峰 1 次 = 17.7s 全网冻结;修复后零尖峰,见 §8.1。 +133.5ms 为压力启动瞬态单帧(FTP 连接建立与帧周期交叠),远低于 500ms 尖峰阈值。) ### 6.4 全段基线总表 @@ -404,27 +420,29 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故 |---|---|---|---|---|---|---| | **L1** `spi_cmd_*` | SPI 字节命令(3 条) | 10 / 15 / 15µs | 10~16µs | 100 | 40/100µs | OK | | **L2** `spi_dma_*` | SPI DMA 读(4/64/1024/2048B) | 20 / 114 / **1611** / 3208µs | ±2µs | 100 | 见 §6.1 | OK | -| **L3** `chunk_wait` | 写发送缓冲 → `SENBUF_FREE`(每 chunk) | **219µs** | 213/381µs | 64 | 10ms/500ms | OK | -| **L5** `queue_rt_recv` | 调用方 `net_recv(DONTWAIT)` 队列全程 | **5997µs** | 5513/6033µs | 20 | 10ms/100ms | OK | -| **L5** `queue_rt_send` | 调用方 `net_send` 队列全程 | **987µs** | 838/1209µs | 20 | 10ms/100ms | OK | -| **L6** `req2first_mcu` | 10B 请求到齐 → 回显发出(MCU 侧) | **319µs** | 308/338µs | 10 | 20ms/200ms | OK | -| **L7** `fullframe_mcu` | 9B 请求 → 3209B 全帧交给芯片 | **6028µs** | 5991/6066µs | 10 | 50ms/500ms | OK | -| **L8** `prod_cycle_mcu` | **生产路径**:LCDMEM 取帧+组帧+net_send(MCU 净成本) | **7142µs** | 7111/7179µs | 50 | 20ms/200ms | OK | -| **L10** `logtax_line` | 一行 60 字符 `printf` @115200 | **4396µs** | 4394/4422µs | 10 | 10ms/25ms | OK(D6 量化) | -| **L11** `ui_loop` | uiTask 生产循环实测周期 | **10986µs** | 10970/21000µs | 120 | 25ms/50ms | OK | +| **L3** `chunk_wait` | 写发送缓冲 → `SENBUF_FREE`(每 chunk) | **219µs** | 213/378µs | 64 | 10ms/500ms | OK | +| **L5** `queue_rt_recv` | 调用方 `net_recv(DONTWAIT)` 队列全程 | **1223µs** | 1194/1223µs | 20 | 10ms/100ms | OK | +| **L5** `queue_rt_send` | 调用方 `net_send` 队列全程 | **988µs** | 840/1216µs | 20 | 10ms/100ms | OK | +| **L6** `req2first_mcu` | 10B 请求到齐 → 回显发出(MCU 侧) | **986µs** | 979/1015µs | 10 | 20ms/200ms | OK | +| **L7** `fullframe_mcu` | 9B 请求 → 3209B 全帧交给芯片 | **6614µs** | 6546/6649µs | 10 | 50ms/500ms | OK | +| **L8** `prod_cycle_mcu` | **生产路径**:LCDMEM 取帧+组帧+net_send(MCU 净成本) | **6707µs** | 6701/6757µs | 50 | 20ms/200ms | OK | +| **L10** `logtax_line` | 一行 60 字符 `printf` @115200 | **4402µs** | 4396/8779µs | 10 | 10ms/25ms | OK(D6 量化) | +| **L11** `ui_loop` | uiTask 生产循环实测周期 | **10986µs** | 10951/11022µs | 120 | 25ms/50ms | OK | | **L9** `relisten` | 断线后自动重监听耗时(MCU 侧,修复后) | **89000µs** | 89000µs ×3 | 3 | 100ms/500ms | OK | -| **L4/L8** peer cycle | 生产客户端完整帧周期(发→收齐 3209B) | **66.0ms** | 53.3/77.4ms | 65 | — | 见 §7 | -| **Δ** | `peer cycle(设备) − peer cycle(模拟器)` | **59.2ms** | — | 65/50 | ≤80ms | 见 §7.1 | +| **L4/L8** peer cycle | 生产客户端完整帧周期(发→收齐 3209B) | **61.6ms** | 50.4/69.8ms | 50 | — | 见 §7 | +| **Δ** | `peer cycle(设备) − peer cycle(模拟器)` | **54.8ms** | — | 50/50 | ≤80ms | 见 §7.1 | -数据来源:L1/L2 = §6.1;其余 MCU 侧 = M2 run15 / M3 串口 `[LAT]` 行 -(`m2_data/m2_serial_excerpt_run15.txt`、`m3_data/` 各 JSON);peer 侧 = `m3_data/*.json`。 +数据来源:L1/L2 = §6.1;其余 MCU 侧 = M2 B2 档(200ms、per-recv 日志已删)/ M3 静默档的串口 `[LAT]` 行 +(`m2_data/m2_quiet_r200.json`、`m3_data/m3_dev_quiet_r200.json`);A/B 对照档 = `m2_quiet_r500.json`(旧条件); +peer 侧 = `m3_data/m3_dev_*_r200.json`。旧 run15 摘录(`m2_serial_excerpt_run15.txt`)保留作 A/B 历史对照。 ### 6.5 重锁规则 - warn ≈ 2×med,crit ≈ 2×warn(兼顾板间/温度漂移与回归灵敏度:SPI 时钟减半 → 超 warn; 再减半 → 超 crit;DMA 超时 1s → 必超 crit); - M2 各段 warn ≈ 现状 ×1.7~10(保留回归灵敏度),crit 取"明显故障"档; - `chunk_wait` 以 500ms spike 为 crit(D1 重传指纹); + `chunk_wait` 以 500ms spike 为 crit(旧 500ms 周期的重传指纹;P0-a 后单次重传台阶 = 200ms, + 低于 crit,弱网需看**连续台阶**而非单点); - 换板/换固件重跑后,任何段超 warn → 重测确认后按实测重锁本表。 --- @@ -435,25 +453,26 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故 同一客户端(`latency_peer.py --mode remo`,100ms 节拍)对**真机 :7003** 与**PC 模拟器 :7003** 各跑一轮: -| 指标 | 真机(65 帧) | 模拟器(50 帧) | 差值 | +| 指标 | 真机(50 帧静默档) | 模拟器(50 帧) | 差值 | |---|---|---|---| -| 帧周期 total(发请求 → 收齐 3209B) | **66.0ms**(53.3/75.3,max 77.4) | **6.8ms**(0.6/13.1,max 15.7) | **+59.2ms** | -| 首字节 first byte | 13.9ms(8.5/19.1) | 6.7ms(0.5/13.0) | +7.2ms | -| **尾批延迟 tail lag**(末批 → 首批) | **52.6ms**(43.3/61.5) | **0.0ms**(0/0.1) | **+52.6ms** | +| 帧周期 total(发请求 → 收齐 3209B) | **61.6ms**(50.4/69.8,max 69.8) | **6.8ms**(0.6/13.1,max 15.7) | **+54.8ms** | +| 首字节 first byte | 9.6ms(3.2/14.2) | 6.7ms(0.5/13.0) | +2.9ms | +| **尾批延迟 tail lag**(末批 → 首批) | **52.6ms**(44.1/59.1) | **0.0ms**(0/0.1) | **+52.6ms** | | recv 批次数/帧 | 5(8B 头 + 1016 + 1024 + 1024 + **137**) | 2 | — | -**真机 66.0ms 的构成**(三段相加 ≈ 66.5,闭合): +**真机 61.6ms 的构成**(三段相加 ≈ 61.6,闭合): ``` [T+0] 客户端发 9B LCDMEM 请求 -[T+6.8ms] 实测推算:uiTask 10ms 轮询拾取 + netTask 调度(≈ L11 的一半) -[T+13.9ms] 首字节到达 = 6.8 + MCU 净处理 7.1ms(prod_cycle_mcu:取 1bpp + 组帧 + net_send 4 分块) -[T+66.0ms] 全帧收齐 —— 最后的 137B 尾巴比前三批(1024B×3,前 4ms 内到齐)晚 52.6ms +[T+2.3ms] 实测推算:uiTask 10ms 轮询拾取 + netTask 调度(P0-b 删日志后 6.8→2.3ms) +[T+9.6ms] 首字节到达 = 2.3 + MCU 净处理 6.7ms + 首批线路段 + (prod_cycle_mcu:取 1bpp + 组帧 + net_send 4 分块) +[T+61.6ms] 全帧收齐 —— 最后的 137B 尾巴比前三批(1024B×3,前 4ms 内到齐)晚 52.6ms ``` - 前三批 1024B 在**首字节后约 4ms 内**全部到齐; -- 第 4 批只有 **137B = 3209 − 3×1024**,比前三批晚 **52.6ms**(与负载无关:压力档 tail 中位 52.2ms); -- **MCU 侧把 3209B 全部交给芯片只要 7.1ms** → 慢的不在 MCU,在芯片协议栈的尾段发送/ACK 交互。 +- 第 4 批只有 **137B = 3209 − 3×1024**,比前三批晚 **52.6ms**(与负载无关:压力档 tail 中位 50.2ms); +- **MCU 侧把 3209B 全部交给芯片只要 6.7ms** → 慢的不在 MCU,在芯片协议栈的尾段发送/ACK 交互。 ### 7.2 交叉对照(三条独立证据 → 归因) @@ -513,8 +532,9 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故 ### 7.5 队列与调度:静默档不存在台阶 -- **L5 队列往返**:收 5997µs / 发 987µs —— 与 netTask 10ms 轮询节拍同量级,属**调度周期**而非排队拥塞; - `queue_rt_send` 987µs ≈ 1 个 chunk(1611µs)量级,发送路径没有额外排队; +- **L5 队列往返**:收 1223µs / 发 988µs(P0-b 后;旧值 5997/987µs)——收段 ≈ 1 个 netTask 循环周期量级, + 属**调度周期**而非排队拥塞(旧收值 5997µs 含 per-recv 日志税 4.4ms/行,已移除); + `queue_rt_send` 988µs ≈ 1 个循环周期,发送路径没有额外排队; - **L3 chunk 级**:219µs ≈ 每 chunk SPI 成本的 1/7 → **芯片 TX 缓冲不是瓶颈**,SPI 搬运才是; - **L11 uiTask 周期**:10986µs(= osDelay(10) + 渲染开销 ≈ 1ms)→ **LVGL 渲染只占约 1ms/帧**, uiTask 不是延迟来源; @@ -541,7 +561,7 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故 | **D18** | 多打点站点共用全局探针窗口 → 跨段污染(测试工装) | **已修复** | 探针窗口串行全局,prod/relisten 段读出 ui_loop 的 ~11ms 值 | `lat_probe_add_seg()` 按段名过滤 | run17 对照 | | **D19** | Phase 14 漏调 `lat_time_init()` → DWT 恒 0 假绿(测试工装) | **已修复** | 时基未使能 → 三段全 0 却 `verdict=OK` | 补初始化 + `med==0` 判无效 | run16 对照 | | **D20** | FTP 开机首个会话的第 2 个数据连接失败(425) | **已定位未修**(暂缓) | 延迟 DISCONNECT 事件与首次 `net_accept` 的先后竞态(详见 §8.2) | 未实施;保留安全硬化(陈旧 DISCONNECT 甄别 + 2 字节状态缓冲越界修复);两次不稳定修法已回退 | 复现脚本 `test/ftp_regression.py` | -| **E-02** | 空闲 FTP 控制连接头阻塞冻结 netTask(= §10.1 的 D3) | **已修复** | `lftpd` 控制行 `read_line` 走阻塞 `net_recv(0)`,netTask 是全部 socket 操作的唯一执行者 → 单会话可冻结全网最长 30s+ | 控制行/数据读改**分片有界读**(`net_recv_to` 5ms 片 + 每片 `vTaskDelay(1)` 让出,总预算仍 30s) | 受压帧 **17.7s → med 74.7ms / max 106.8ms,零尖峰** | +| **E-02** | 空闲 FTP 控制连接头阻塞冻结 netTask(= §10.1 的 D3) | **已修复** | `lftpd` 控制行 `read_line` 走阻塞 `net_recv(0)`,netTask 是全部 socket 操作的唯一执行者 → 单会话可冻结全网最长 30s+ | 控制行/数据读改**分片有界读**(`net_recv_to` 5ms 片 + 每片 `vTaskDelay(1)` 让出,总预算仍 30s) | 受压帧 **17.7s → med 65.0ms / max 133.5ms,零尖峰**(2026-09-22 P0-a/P0-b 代码下复验) | ### 8.2 D20 详情(已定位,未修复) @@ -612,7 +632,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 | 观测现象 | 首要指向 | 动作 | |---|---|---| | 每帧都**稳定**慢 ≈150~300ms | 结构性基线(§10.1 的 D2/D5/D6/D8) | 跑 §5 的 Phase 13/14 对照基线 | -| **间歇**卡,且 ≈500ms 的整数倍 | **D1** 丢包重传 | Wireshark `tcp.analysis.retransmission`;查 PHY/网线/Wi-Fi | +| **间歇**卡,且 ≈200ms 的整数倍(旧固件 500ms) | **D1** 丢包重传 | Wireshark `tcp.analysis.retransmission`;查 PHY/网线/Wi-Fi | | **间歇**整屏冻结数秒~数十秒 | **E-02** 头阻塞(已修)/ D10 重连(已修)/ 回归 | 查 FTP/对时会话是否挂着;核对 §8.1 修复在位 | | 只在开 FTP / 对时后卡 | E-02 + 单连接 socket 争用 | 临时停 ftpTask/timeSyncTask 对照 | | 换网口/换线/换 PC 就好 | D7 物理链路 | §10.2-S3 拓扑纪律 | @@ -622,8 +642,8 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 | 现象(段超标) | 首要怀疑 | 动作 | |---|---|---| | L1/L2 超 crit | SPI 走线/PCB/SPI2 分频或 DMA 配置 | 对照 `docs/问题记录/CH395F_Trap_Records.md`;逻辑分析仪抓 SCK/CS | -| L3 spike ≥500ms | **D1 重传 / D7 链路** | Wireshark `tcp.analysis.retransmission`;查 PHY 协商/网线/Wi-Fi | -| L3 基线(非 spike)抬高 | 芯片发送路径 / 中断响应 | 对照 CH395F 手册 §5.17/5.18;`GET_CMD_STATUS` 逐段核对 | +| L3 spike ≥200ms(连续台阶;旧固件 500ms) | **D1 重传 / D7 链路** | Wireshark `tcp.analysis.retransmission`;查 PHY 协商/网线/Wi-Fi | +| L3 基线(非 spike)抬高 | 芯片发送路径 / 中断响应 | 对照 CH395F 手册 §5.17/5.18(注意:状态寄存器**不被 SET 类命令更新**,`GET_CMD_STATUS` 恒读到 RESET 的 0x10 陈旧残留,2026-09-22 台架实证——不可用作 SET 值验收) | | L5 压力档爆表 | **E-02 头阻塞(已修)** → 回归 | 定位触发源(阻塞 recv 的 FTP/对时);核对 `net_recv_to` 分片在位 | | L5/L6 静默档抬高 | D5 调度(任务抢占/节拍) | 查任务优先级与 osDelay;`stack_report.py` 核对栈水位 | | L6/L7 整体抬高且 L1~L5 正常 | 线路+PC 段(L4) | Wireshark 段间间隙;`Δ` 对照定位 MCU 侧净贡献 | @@ -633,6 +653,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 | **L7 一直超时 / peer 报 `l7_crc.fail`** | **D15**:帧格式不一致 / peer 超读 | 对照 `ui_net_sink.c` 的 `remo_send`/`remo_handle`(§8.1 D15) | | **会话跑完一段后无限循环、peer 空等 300s** | **D16**:Phase 13 状态机迁移目标错 | 核对顺序 L5→L3→L10→L6→L7→DONE(§8.1 D16) | | **`[LAT]` 段行缺失/截断、wait-idle 判不出空闲** | **D12-b**:热路径日志洪水 | 删除 net 热路径逐调用日志(§8.1 D12-b) | +| **开机日志连续丢行**(含必检标记 `net init: OK` 等)但系统健康 | **日志并发竞态**:多任务并发 `printf` → 非重入 `fputc`/`HAL_UART_Transmit` 丢整行、UART 状态短暂卡住(2026-09-22 台架实证:boot 时 testTask 启动行与 netTask 日志并发 → 连续 4 行丢失、~2s 后自恢复) | 必现证据行采用"静默采集 + 延迟到安静窗口打印"模式(范例:`net_retrans_status_log` 在 PHY 行之后打印);根治 = S8 日志非阻塞/串行化(§10.2) | | **`relisten` 段 FAIL、断线固定 ~588ms** | **D10** 回归(退回 `osDelay(500)`) | 核对 `net_relisten_try`/`net_relisten_retry_tick` 非阻塞重试在位(§8.1 D10) | | **远端显示整帧卡住十几秒后自恢复** | **E-02** 回归 | 核对 `net_recv_to` 5ms 分片 + 让出在位(§8.1 E-02) | | **INIT 应答帧字节数字段恒为 0** | **D17** 回归 | 核对 `remo_send_init` 发满 8B(§8.1 D17) | @@ -640,7 +661,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 | **`[LAT]` 多段数值雷同 / 全 0 却 verdict=OK** | **D18/D19**(测试工装) | 核对 `lat_probe_add_seg` 段名过滤 + `lat_time_init` 调用 + `med==0` 判无效 | | **连接建立后 15~30s 无流量即被 RST** | **D13**:芯片空闲超时(芯片行为) | 客户端须容忍并重连(peer `--wait` 重试是正常路径) | | **peer 重连后 MCU 状态滞留、新连接字节被吞** | **D14**:芯片静默回收 Socket | `net_resync_listen`/`net_relisten` 自愈路径核对 | -| L8 超而 L7 正常 | 生产路径附加成本(uiTask 节拍/LVGL/日志) | 对照 L10/L11 与 §10.1(渲染已排除;日志税待办 P0-b/S8) | +| L8 超而 L7 正常 | 生产路径附加成本(uiTask 节拍/LVGL/日志) | 对照 L10/L11 与 §10.1(渲染已排除;per-recv 日志已删,S8 非阻塞日志仍待办) | | Δ 显著 >80ms | CH395F 栈净开销异常 | 回到 L1~L9 逐段排查 | --- @@ -651,23 +672,22 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 | # | 原因 | 实测验证(2026-09-22 台架) | 当前状态 | |---|---|---|---| -| D1 | CH395F TCP 重传固定 500ms 周期(8 次 = 4s 窗口;非 RTT 自适应) | 台架链路(有线 100M 全双工)三轮零重传尖峰 → 台架无丢包;**弱网(Wi-Fi/双工不匹配)仍是秒级卡顿首要嫌疑**,0.5/1.0/1.5s 台阶 = 500ms 粒度指纹 | **未修**(仍 `ch395f_set_retrans_count(8)` + `period(500)`);待办 P0-a(周期 200ms,需台架验证) | +| D1 | CH395F TCP 重传固定周期(非 RTT 自适应) | 台架链路(有线 100M 全双工)多轮零重传尖峰 → 台架无丢包;**弱网(Wi-Fi/双工不匹配)仍是秒级卡顿首要嫌疑**,200ms 粒度台阶 = 重传指纹(旧固件 500ms) | **已修(P0-a,2026-09-22)**:`NET_RETRANS_PERIOD_MS` 500→**200**(窗口 8×200=1.6s,原 4s)。台架验收说明:`GET_CMD_STATUS` 对 SET 类命令无判别力(500/2000ms 超限对照均读 0x10 陈旧残留,§9.2)→ 接受性以手册范围(≤1000ms)+ 全套件零回归(§6.2/§6.3)+ 与 500ms 行为同构为准 | | D2 | 3209B × 1KB 发送 FIFO 停止等待(4 次串行分块握手,期间 netTask 全程占用) | `chunk_wait` 219µs/块 ≈ SPI 搬运成本的 1/7 → 握手本身**不是瓶颈**;每帧固定成本小(MCU 净 7.1ms) | 基线成本,可接受;根治 = 差量/RLE + 帧版本号(待办 S2) | | D3 | netMsgQueue 头阻塞(= §8.1 E-02) | 已量化:一条空闲 FTP 控制连接冻结全网 17.7s | **已修复**(5ms 分片有界读 + 让出,§8.1) | | D4 | PC 端延迟 ACK 与"每段等 ACK"停止等待交互 | `--ack-fast` 带内实验证实:关掉延迟 ACK 尾批自行消失(52→3.9ms) | **已客户端侧解决**(生产客户端关延迟 ACK/轻推兜底,§7.4) | -| D5 | uiTask 节拍:10ms 循环 + 每拍一次 64B recv + step 在 poll 前 | `ui_loop` 10986µs ≈ 设计值(渲染 ~1ms);拾取调度 ~6.8ms | 基线行为;可选优化 S7(poll 前置 + while 排空),低优先 | -| D6 | 阻塞式日志在关键路径(fputc 逐字节 @115200) | `logtax_line` 4396µs/行;`net_recv_locked` 的 per-recv 日志仍在 | **部分待办**(P0-b:删/降级 per-recv 日志;S8:日志改非阻塞) | +| D5 | uiTask 节拍:10ms 循环 + 每拍一次 64B recv + step 在 poll 前 | `ui_loop` 10986µs ≈ 设计值(渲染 ~1ms);拾取调度 ~2.3ms(P0-b 删 per-recv 日志后,原 ~6.8ms) | 基线行为;可选优化 S7(poll 前置 + while 排空),低优先 | +| D6 | 阻塞式日志在关键路径(fputc 逐字节 @115200) | `logtax_line` 4402µs/行;per-recv 日志已删(2026-09-22):`queue_rt_recv` 5997→1223µs、帧周期 66.0→61.6ms、首字节 13.9→9.6ms | **部分已修(P0-b,2026-09-22)**;S8 非阻塞日志仍待办(同时是开机日志并发丢行 §9.2 的根治项) | | D7 | 物理链路:强制 100M 全双工 vs 交换机自协商 → 双工不匹配静默丢包 | 台架 `PHY: 100M FULL` 成立、零尖峰 → 台架干净 | 现场排查项(S3):核对开机日志 PHY 行 + 交换机端口强制全双工 + 验证 PC 有线直连 | | D8 | 客户端固定成本:100ms 拉取节拍、按键后不立即取帧、1bpp→PNG→base64→WS 编码链 | 生产客户端优化后:帧耗时 20.7ms、显示帧率 ~9fps | 部分已优化(延迟确认抑制已上线);其余待办 S9(按键后立即取帧/不传 PNG/自适应节拍)——客户端仓库 | -| D9 | LVGL 全量渲染(RENDER_MODE_FULL)+ uiTask BelowNormal 易被抢占 | `ui_loop` 显示渲染仅 ~1ms/帧 | **已排除**(非瓶颈;调优先级/栈无收益,§7.5) | -| D10 | 断线重连路径 `osDelay(500)`(netTask 忙等) | 已量化:relisten 588ms×3 且冻结 netTask | **已修复**(非阻塞延迟重试 → 89ms,§8.1) | ### 10.2 待办优化项(按性价比排序,均未实施) 1. **D20 数据 Socket 轮换**(§8.2)——唯一未修的功能性缺陷;现场可用客户端重试 425 规避; -2. **P0-a** `ch395f_set_retrans_period(500) → 200`(一行级;治 D1 症状:单次丢包代价 500→200ms; - 总窗口 8×200=1.6s,链路真断时判失败更快;手册 §5.18 允许 ≤1000ms,最小值未标注 → **需台架验证 200 被接受**); -3. **P0-b** 删除/降级 `net_socket.c` 的 per-recv `DBG_INFO`(每帧省 ~4.4ms netTask 阻塞,顺带减 syslog 噪声); +2. **~~P0-a~~ 已实施(2026-09-22)**:`NET_RETRANS_PERIOD_MS` 500→200 + `GET_CMD_STATUS` 一次性验收检查 + (实测该状态对 SET 类命令无判别力,见 §10.1 D1);全套件复验零回归(§6.2/§6.3); +3. **~~P0-b~~ 已实施(2026-09-22)**:删除 `net_socket.c` per-recv `DBG_INFO`;实测 `queue_rt_recv` −80% + (5997→1223µs)、生产帧周期 −4.4ms(66.0→61.6ms)、首字节 −4.3ms(13.9→9.6ms); 4. **S1** 超时参数分档:`NET_SEND/RECV_TIMEOUT_MS` 全局一刀切 → 按服务分离(远显短超时+非阻塞,FTP 保留长超时); 5. **S2** 差量/RLE + 帧版本号 + 由拉改推(**根治,收益最大**:典型变化 <100B → 单段一帧,延迟 ≈ 一个 RTT; 稳态带宽 32KB/s → ≈0;D1 影响面 4 段 → 1 段;新命令走同一帧格式与 CRC,旧客户端兼容); @@ -682,6 +702,10 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 11. **M4**(可选)`test/run_latency_test.py` 一键编排(open/clear/flash/wait-idle/peer/collect/merge/verdict)——待排期; 12. **M5**(可选,在役设备)非独占采样器:事件触发、10s 旁路打点入 syslog——设计预留; 13. 协议补位(尾批退路,仅当客户端无法改动时;见 §7.4)。 +14. **日志并发保护(2026-09-22 新增,与 S8 同源、优先级上调)**:开机多任务并发 `printf` 丢整行 + (实测 §9.2:必检标记 `net init: OK` 曾被竞态吞掉 → 影响开机验收可靠性)。过渡:必现证据行按 + "静默采集 + 延迟到安静窗口打印"模式(范例 `net_retrans_status_log`);根治 = S8(串口 TX 环形缓冲 + + 中断/DMA,溢出丢弃策略需定义)。 --- @@ -708,12 +732,16 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复 | `m2_data/m2_quiet.json` | M2 安静档 peer 侧(run15 最终代码):L3~L7 端到端 + 逐帧尾批明细 | | `m2_data/m2_quiet_run13.json` | M2 run13(独立 PASS 对照) | | `m2_data/m2_quiet_run14.json` | M2 run14(仅 peer 侧有效;MCU 侧因热路径日志洪水不作基线,D12-b) | -| `m2_data/m2_serial_excerpt_run13/15.txt` | M2 串口 `[LAT]`/`[NET]` 证据片段 | +| `m2_data/m2_serial_excerpt_run13/15.txt` | M2 串口 `[LAT]`/`[NET]` 证据片段(旧基线,A/B 历史对照) | +| `m2_data/m2_quiet_r500.json` | 2026-09-22 A/B 对照档 B1(500ms + per-recv 日志 = 旧基线条件;复跑与 run15 重合 ±0.2%) | +| `m2_data/m2_quiet_r200.json` | **2026-09-22 M2 重锁基线** B2(200ms、per-recv 日志已删 = 当前代码) | | `m2_data/README.md` | M2 数据说明(逐帧尾批明细、方法学约束) | | `m3_data/m3_dev_quiet.json` | 真机 65 帧生产周期(D10/E-02/D17 修复前基线) | | `m3_data/m3_dev_quiet_fixed.json` | 真机 65 帧(修复后:帧周期 65.7ms、relisten OK、INIT framebytes=3200) | | `m3_data/m3_dev_stress.json` | E-02 压力档(修复前:17.7s 尖峰) | | `m3_data/m3_dev_stress_fixed.json` | E-02 压力档(修复后:med 74.7ms / max 106.8ms,零尖峰) | +| `m3_data/m3_dev_quiet_r200.json` | **2026-09-22 M3 静默档重锁基线**(50 帧,P0-a/P0-b 代码:帧周期 61.6ms) | +| `m3_data/m3_dev_stress_r200.json` | **2026-09-22 M3 压力档重锁基线**(45 帧,第 15 帧起 FTP stress:med 65.0ms / max 133.5ms,零尖峰) | | `m3_data/m3_sim_quiet.json` | 模拟器基线 50 帧(Δ 对照,tail=0) | | `m3_data/m3_tail_ackprobe.json` | 尾批实验 ①:帧未收齐即回 1 字节(捎带 ACK)→ tail 3.9ms | | `m3_data/m3_tail_ackfast.json` | 尾批实验 ②:Windows 立即 ACK(不发探测字节)→ tail 3.9ms | diff --git a/test/ch395f_test.h b/test/ch395f_test.h index 80ab4515..7e5585a6 100644 --- a/test/ch395f_test.h +++ b/test/ch395f_test.h @@ -63,9 +63,9 @@ extern "C" { //#define ENABLE_PHASE10_TESTS /* [网] 边界条件测试 */ //#define ENABLE_PHASE11_TESTS /* [网] KeepAlive 超时断开测试 */ /* ---- 链路时延基线(M1;分段/阈值见 docs/测试说明/链路延迟测试说明.md)---- */ -//#define ENABLE_PHASE12_TESTS /* [硬] SPI 字节命令 / DMA 时延基线(L1/L2,无需 PC)—— M1 已完成,基线见说明文档 §4.1 */ +//#define ENABLE_PHASE12_TESTS /* [硬] SPI 字节命令 / DMA 时延基线(L1/L2,无需 PC)—— M1 已完成,基线见说明文档 §6.1 */ /* ---- 链路时延(M2/M3;分段/阈值见 docs/测试说明/链路延迟测试说明.md)---- */ -//#define ENABLE_PHASE13_TESTS /* [网] 芯片 + 队列时延(L3~L7/L10,需 PC peer)—— M2 已完成,基线见说明文档 §4.2 */ +//#define ENABLE_PHASE13_TESTS /* [网] 芯片 + 队列时延(L3~L7/L10,需 PC peer)—— M2 已完成,基线见说明文档 §6.2 */ #define ENABLE_PHASE14_TESTS /* [网] 生产路径时延(L8~L11 + 模拟器 Δ)—— M3,需 peer --mode remo(:7003) */ #if defined(ENABLE_PHASE1_TESTS) || defined(ENABLE_PHASE2_TESTS) || \ diff --git a/test/test_config.h b/test/test_config.h index 14513bce..b04bf19b 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -23,11 +23,10 @@ extern "C" { #include /* === 选择当前构建的测试套件(三选一,或都注释 = 正常产品构建)=== - * 2026-09-22:M2(链路时延 Phase 13,NET 层,需 PC peer)交付 —— - * 当前启用 CH395F 套件 + Phase 13(独立运行,勿与其他 Phase 混选)。 - * 执行:先起 test/latency_peer.py --mode net --port 8080,再 @test 烧录。 - * 恢复产品构建 = 注释掉下面两行(TEST_SUITE_CH395F 与 ch395f_test.h 的 - * ENABLE_PHASE13_TESTS)。详见 docs/测试说明/链路延迟测试说明.md §5.2。 */ + * 2026-09-22:M1~M3(链路时延 Phase 12/13/14,阶段表见说明文档 §4.2)交付 —— + * 当前启用 CH395F 套件 + Phase 14(生产路径时延,M3 基线已锁定,2026-09-22 重锁)。 + * 恢复产品构建 = 注释掉下方 TEST_SUITE_CH395F 一行(ch395f_test.h 的阶段宏 + * 仅在套件启用时生效,无需另改)。详见 docs/测试说明/链路延迟测试说明.md §4.2/§5。 */ #define TEST_SUITE_CH395F //#define TEST_SUITE_STORAGE //#define TEST_SUITE_GD5F