SG2002 WiFi 新同步原语的影响 - Antareske/tgoskits GitHub Wiki

SG2002 WiFi:新同步原语的影响、信用事件化尝试与 raw 修复评估(2026-08-22)

本文写于 2026 年 8 月,记录写作当时的代码状态;文中的文件路径与实现细节与当前主线已有出入。

本文围绕一次主线同步原语重构(dev 的锁统一工作)展开,记录它对 wifi 驱动的三重影响、信用事件化尝试的过程与结果、以及当前修复形态的评估与后续方向。所有 iperf3 测试均为同一块板、同一 AP、同一测试机,服务端跑在板卡上(iperf3 -s),上行指测试机→板卡方向(板卡为接收方),下行指板卡→测试机方向(板卡为发送方)。


一、主线同步原语重构对 wifi 驱动的影响面

1.1 发生了什么

dev 主线的一次锁统一重构把 wifi 驱动使用的全部总线锁,从"原始自旋锁"(获取/释放时什么都不做,不改变任务的运行环境)机械替换为"抢占禁用锁"(获取时禁止内核抢占,即当前任务在锁内不会被调度器换走)。对单核板卡而言,两类锁的"互斥"部分是一样的(都没有真正的并发保护),唯一的差别就是后者每获取一次锁就多一层"禁止换班"的约束。

这个看似中性的替换,实际产生了三重影响。

1.2 影响一:吞吐下降约 20%,且下行被"量化"

变基后的板测与变基前基线对比:上行 9.29/9.61 vs 11.2/12.0,下行 8.54 vs 11.0,双向 3.23/3.34 vs 5.37/5.81(且首次双向出现 3 次流控超时告警)。

下行原始日志(注意大多数区间恰好钉在 8.38-8.39 Mbps = 1.00 MB/s):

[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  1.00 MBytes  8.38 Mbits/sec    0   0.00 Bytes
[  5]   1.00-2.00   sec  1.00 MBytes  8.38 Mbits/sec    0   0.00 Bytes
[  5]   2.00-3.00   sec  1.00 MBytes  8.39 Mbits/sec    0   0.00 Bytes
[  5]   3.00-4.00   sec  1.00 MBytes  8.38 Mbits/sec    0   0.00 Bytes
[  5]   4.00-5.01   sec  1.00 MBytes  8.32 Mbits/sec    0   0.00 Bytes
[  5]   5.01-6.00   sec  1.00 MBytes  8.47 Mbits/sec    0   0.00 Bytes
[  5]   6.00-7.00   sec  1.12 MBytes  9.44 Mbits/sec    0   0.00 Bytes
[  5]   7.00-8.00   sec  1.00 MBytes  8.38 Mbits/sec    0   0.00 Bytes
[  5]   8.00-9.00   sec  1.00 MBytes  8.38 Mbits/sec    0   0.00 Bytes
[  5]   9.00-9.95   sec  1.00 MBytes  8.88 Mbits/sec    0   0.00 Bytes
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-9.95   sec  10.1 MBytes  8.54 Mbits/sec    0            sender

吞吐"钉死"在 1.00 MB/s 步进是节奏被定时器接管的指纹:每发一个包要经过几十次加锁解锁,每次锁内都不允许换班,任务之间的交接时机被这些约束窗口整体推迟,wifi 线程的收发节奏从"数据来了就动"退化成"定时巡检才动"。

双向聚合吞吐与变基前持平(总能力没降),说明问题不在能力而在节奏。

1.3 影响二:正确性契约违反(板测实证 panic)

wifi 驱动的总线锁被设计为跨整个传输持有,包括传输末尾"等硬件完成"的睡眠等待(等待期间任务应当睡着、让 CPU 给别人用)。这在原始自旋锁语义下完全合法——锁不改变运行环境,任务可以正常睡觉。

抢占禁用锁把这件事变成了非法操作:禁止换班的锁里不允许睡觉。这在板测中被实证——信用事件化尝试(见第二部分)改变了收发节奏后,某次传输的完成等待恰好没在快速路径内命中,任务带着锁进入睡眠等待,当场触发内核检查:

panicked at os/arceos/modules/axtask/src/api.rs:599:5:
sleeping or rescheduling is not allowed in atomic context: caller=os/arceos/modules/axruntime/src/wifi_glue.rs:98:22, reasons=[preempt_disabled], irq_enabled=true, preempt_count=1, cpu_id=0, task_id=Some(6)

(preempt_count=1 正是"持着一把抢占禁用锁"的痕迹。这不是新代码引入的错误路径——锁跨睡眠等待的写法一直存在,是重构把这条老路从合法变成了违规。任何改动收发时序的工作都可能踩中它。)

1.4 影响三:锁型选择被锁死

wifi 驱动的另一类锁(收发数据队列等"边界锁")是在关中断环境下被网络栈获取的(网络栈持锁穿越驱动收发链)。这使"睡眠锁"(获取时允许任务睡觉、但也因此在关中断下必炸)对边界锁物理上不可用——板测同样实证过一次启动 panic。

于是三条路里两条被堵死:睡眠锁不行(关中断下必炸)、抢占禁用锁代价沉重(1.2/1.3 的全部问题)。唯一同时满足"关中断下可获取、锁内可睡觉、不改变调度节奏"的语义,就是重构前的原始自旋锁。

1.5 根因确认

对照实验:仅把锁恢复为原始自旋语义、其余不动,上行 12.3 / 下行 11.1 / 双向 5.65+6.28、零告警——三方向全部回到变基前水平。重构改写锁语义是上述全部问题的根因。


二、信用事件化尝试,与 raw 修复后的表现

2.1 信用事件化是什么

wifi 芯片的发送受"信用"限制:芯片内有一块有限缓冲(信用 = 空闲单元数),发送前必须确认有足够空闲。旧实现里,信用不足时发送线程会空转 50 次读寄存器 + 让出 CPU,醒来后也没有人通知它"信用恢复了"——只能干等下一次定时巡检。

本次尝试把"信用恢复"变成事件:接收线程每排空一批数据后顺手看一眼信用值,够了就摇发送线程的铃。发送线程信用不足时不再空转,改为登记门铃后睡觉。这一步不新增任何定时兜底,是一次纯事件驱动的实验。

2.2 事件化首先踩中了 1.3 的炸弹

事件化改变了发送节奏(信用恢复当刻立即续写,不再有 50 次空转的间隔),某次传输的完成等待越过了快速路径,任务带着抢占禁用锁进入睡眠——触发 1.3 的 panic(第二次测试启动后)。这次意外实证了隐患的存在:重构后"持锁等传输完成"这条路是随时会炸的,任何时序变化都可能成为引信。

2.3 raw 修复后:三方向全量日志

将总线锁恢复为原始自旋语义后(改动三行锁类型声明,全部 69 处加锁调用点不变),板测一次跑完三方向、零异常:

上行(板卡为接收方):

[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec  1.50 MBytes  12.6 Mbits/sec
[  5]   1.00-2.01   sec  1.50 MBytes  12.5 Mbits/sec
[  5]   2.01-3.00   sec  1.50 MBytes  12.6 Mbits/sec
[  5]   3.00-4.00   sec  1.50 MBytes  12.6 Mbits/sec
[  5]   4.00-5.00   sec  1.50 MBytes  12.6 Mbits/sec
[  5]   5.00-6.00   sec  1.50 MBytes  12.6 Mbits/sec
[  5]   6.00-7.00   sec  1.62 MBytes  13.7 Mbits/sec
[  5]   7.00-8.00   sec  1.50 MBytes  12.6 Mbits/sec
[  5]   8.00-9.00   sec  1.62 MBytes  13.6 Mbits/sec
[  5]   9.00-10.00  sec  1.50 MBytes  12.6 Mbits/sec
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.02  sec  15.2 MBytes  12.8 Mbits/sec                  receiver

下行(板卡为发送方,Retr 全程为 0):

[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  1.25 MBytes  10.5 Mbits/sec    0   0.00 Bytes
[  5]   1.00-2.00   sec  1.25 MBytes  10.5 Mbits/sec    0   0.00 Bytes
[  5]   2.00-3.00   sec  1.38 MBytes  11.5 Mbits/sec    0   0.00 Bytes
[  5]   3.00-4.00   sec  1.25 MBytes  10.5 Mbits/sec    0   0.00 Bytes
[  5]   4.00-5.00   sec  1.25 MBytes  10.5 Mbits/sec    0   0.00 Bytes
[  5]   5.00-6.00   sec  1.38 MBytes  11.5 Mbits/sec    0   0.00 Bytes
[  5]   6.00-7.00   sec  1.25 MBytes  10.5 Mbits/sec    0   0.00 Bytes
[  5]   7.00-8.00   sec  1.25 MBytes  10.5 Mbits/sec    0   0.00 Bytes
[  5]   8.00-9.00   sec  1.38 MBytes  11.5 Mbits/sec    0   0.00 Bytes
[  5]   9.00-9.99   sec  1.25 MBytes  10.7 Mbits/sec    0   0.00 Bytes
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-9.99   sec  12.9 MBytes  10.8 Mbits/sec    0            sender

双向(RX-S 为板卡接收、TX-S 为板卡发送):

[ ID][Role] Interval           Transfer     Bitrate         Retr  Cwnd
[  5][RX-S]   0.00-1.00   sec   512 KBytes  4.18 Mbits/sec
[  8][TX-S]   0.00-1.00   sec   768 KBytes  6.27 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   1.00-2.00   sec   768 KBytes  6.30 Mbits/sec
[  8][TX-S]   1.00-2.00   sec   640 KBytes  5.25 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   2.00-3.00   sec   768 KBytes  6.29 Mbits/sec
[  8][TX-S]   2.00-3.00   sec   768 KBytes  6.29 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   3.00-4.00   sec   640 KBytes  5.23 Mbits/sec
[  8][TX-S]   3.00-4.00   sec   768 KBytes  6.28 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   4.00-5.00   sec   768 KBytes  6.29 Mbits/sec
[  8][TX-S]   4.00-5.00   sec   640 KBytes  5.24 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   5.00-6.00   sec   768 KBytes  6.29 Mbits/sec
[  8][TX-S]   5.00-6.00   sec   768 KBytes  6.29 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   6.00-7.00   sec   640 KBytes  5.25 Mbits/sec
[  8][TX-S]   6.00-7.00   sec   768 KBytes  6.30 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   7.00-8.00   sec   768 KBytes  6.28 Mbits/sec
[  8][TX-S]   7.00-8.00   sec   768 KBytes  6.28 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   8.00-9.00   sec   768 KBytes  6.30 Mbits/sec
[  8][TX-S]   8.00-9.00   sec   640 KBytes  5.24 Mbits/sec    0   0.00 Bytes
[  5][RX-S]   9.00-10.00  sec   640 KBytes  5.23 Mbits/sec
[  8][TX-S]   9.00-10.00  sec   768 KBytes  6.28 Mbits/sec    0   0.00 Bytes
[ ID][Role] Interval           Transfer     Bitrate         Retr
[  5][RX-S]   0.00-10.02  sec  6.88 MBytes  5.75 Mbits/sec                  receiver
[  8][TX-S]   0.00-10.02  sec  7.12 MBytes  5.96 Mbits/sec    0            sender

2.4 对比与解读

方向 变基前基线 重构后 raw 对照实验 本次(事件化 + raw)
上行 11.2 / 12.0 9.29 / 9.61 12.3 12.8
下行 11.0 8.54(量化钉死) 11.1 10.8
双向 5.37 / 5.81 3.23 / 3.34(3 次告警) 5.65 / 6.28 5.75 / 5.96
异常 无 量化 + 流控告警 无 无(零 panic、零告警)
  • 上行与双向恢复到基线之上:事件化的收益(消除 50 次空转的总线/CPU 占用)叠加 raw 的基线恢复,上行 12.8 与双向 5.75/5.96 均为所有轮次最高;
  • 量化现象消失:重构后下行"钉死在 1.00 MB/s 步进"的指纹在本次日志中完全不见(区间在 10.5-11.5 间正常波动)——这是信用事件化生效的直接证据,收发节奏重新由数据驱动;
  • 下行 10.8 较基线(11.0-11.1)轻微回落约 2%:接收线程现在每排空一批数据多付一次信用检查(一次寄存器读、占用共享总线)。单次样本、幅度在波动范围内,不排除是噪声;若后续复测确认该回落稳定存在,可以按需把信用检查降频(例如每两批查一次),属可调参数而非结构问题;
  • 零 panic、零告警:1.3 的契约炸弹被 raw 拆除,双向首秒的流控超时告警不再出现。

三、下一步:新原语的去留与其它优化

3.1 新原语处理:重做 vs wifi 局部 raw

现状:wifi 局部 raw 已实现(一个新模块 + 三行锁类型声明,69 处调用点不变),板测三方向全部达到或超过变基前基线、零异常。安全论证完整:单核运行;中断处理路径从不取这些锁;关中断环境下获取的边界锁与"锁内睡觉"的总线锁都不改变运行环境,恰是 raw 的合法用途。

重做(结构修复:锁不跨睡眠持有)的价值与成本:它从根上消除"持锁睡觉"的契约问题,让锁型选择重新开放(届时睡眠锁对总线锁也重新可用);但需要拆分 SDIO 传输接口为"发起/等待"两段、配套完成归属协议与中断侧改造,改动面是 raw 的数十倍,且单独不解决性能全恢复(每操作一次的"禁止换班"开销仍在)。它是把锁型从"被迫选择"变成"自由选择"的地基,但不是当前必须。

建议:当前以局部 raw 落地为交付形态(改动小、证据硬、安全论证完整);结构修复列为后续演进项。若后续主线有调整(例如上层不再关中断穿越驱动链、或提供新的锁语义),届时锁型可按板测数据重选,raw 模块是单点可替换的隔离层。

3.2 其它优化探索(按证据与依赖排序)

  1. 发送聚合:厂商驱动的核心流水线机制——把信用值当聚合预算,一次总线写入携带多帧,摊薄每次写入的固定开销。既往优化报告将其估为约 10% 的差距项,与本事件化正交可叠加;
  2. 既往报告的独立补项:SDIO 总线 25MHz→50MHz 并配置 PHY 延迟(报告中下行 +96% 的独立杠杆);兜底巡检周期 10ms→1ms(报告中 +20%,事件化覆盖后影响力下降,可作保险);
  3. 异步化深化:传输完成事件令牌(配合结构修复)、兜底巡检降级为纯安全网并加触发计数(触发趋零即验证事件覆盖完备);
  4. 前提验证:芯片缓冲池是否收发共享(一次板测:发送阻塞时读信用值 → 无发送写入时制造一次接收排水 → 再读信用值)。它决定"接收排水通知发送"这条事件链的收益上限,也决定后续优化该往哪个方向投。