Repository navigation
v0.4.6
Com Bridge v0.4.6
两处输入热路径修复 + 一套可量化的延迟诊断。
修:副机某块屏上鼠标"非常迟滞、手停了光标还在追"
现象(用户实测):副机 2560×1600 屏上移动非常迟滞,同样操作在 1920×1080 屏上正常。
原因在事件流本身,与屏幕像素无关:
- 输入是 UDP,消费端一时跟不上,事件就堆在内核接收缓冲里
(默认 64KB ≈ 3400 条 19 字节事件 ≈ 3 秒的量); - 旧实现逐条取出、逐条注入,每条都要付一次
SendInput的代价,
于是积压只能按"消费速率"慢慢排空 —— 主观上就是光标在追手。
副机的光标从进入边(在 2560 屏上)开始就一直背着这段积压跑,
等到 1920 屏时已经排空,所以"只有那块屏迟滞"。
修复(transport.coalesce_moves):收到一条事件后先看 socket 里还有没有积压,
有就继续攒,再把相邻位移合并成一条注入。
- 光标只需要最终位置:k 条相邻位移等价于 1 条 (Σdx, Σdy),落点不变;
- 合并后一轮只付一次
SendInput,积压立刻塌到最新位置,不再"追手"; - 只合并相邻的移动事件,绝不跨越按键/滚轮 ——
[移动, 点击, 移动]
的顺序即语义,压掉点击就会点错位置; - 没有积压时行为与旧版完全一致(逐条交付),不平白引入延迟。
实测数字(副机 0.4.6,diag_lat 每 5 秒一行,用户在两块屏间正常移动):
接收=797/s 批=3849 最大积压=39 合并=1821 注入均=1.01ms 峰=15.8ms | 光标=(0,636) 屏=2560x1600@0,0
关键在 注入均=1.01ms:SendInput 一次就要约 1ms,而主机上报率约 800~1000 事件/秒
—— 旧实现"每条一注入"正好把消费端顶在 100% 饱和,任何一次系统抖动(峰值 15.8ms)
都会让它落后,落后就只能靠后续慢慢排空,于是"手停了光标还在追"。
合并后一次注入覆盖整批,消费端从饱和降到约一半,两块屏都跟手。
修:主机接多块屏时,越界边落在错误的边缘
主机侧越界判定一直用"面积最大的那块屏",而副机侧用的是整个虚拟桌面。
两块屏并排时,那条边正好在桌面中间 —— 光标走到中间就判"越界",把输入送去副机。
现在两侧统一用 virtual_desktop();多屏时启动日志会打印实际基准与屏数。
新增:管线延迟诊断(默认关闭)
%LOCALAPPDATA%\ComBridge\diag_lat.flag(或环境变量 COM_BRIDGE_DIAG_LAT=1)
存在时,副机每 5 秒打印一行:
[agent][lat] 接收=812/s 交付=794/s 批=… 最大积压=… 合并=… 注入均=0.42ms 峰=3.1ms | 光标=(x,y) 屏=2560x1600@0,0 | hider 隐藏=0.0/s 收起=0.0/s
判读:
| 观察 | 结论 |
|---|---|
接收 远低于主机上报率,最大积压 恒为 1 |
事件在路上就丢了,不是本地慢 |
最大积压 持续 > 1、合并 持续增长 |
确实在排队;本次合并已把积压塌缩成一次注入 |
注入均/峰 本身是毫秒级 |
SendInput 在这块屏/这台机器上就慢(系统/驱动层面) |
hider 隐藏/收起次数快速上涨 |
隐藏器在反复抢前台,与鼠标事件量无关 |
其他
- 输入事件时间戳改用
perf_counter微秒时钟(time.monotonic_ns()在 Windows
上分辨率只有 15ms,无法用来量化延迟)。 - 新增 15 项回归测试(
tests/test_input_batching.py):位移总量守恒、
非移动事件不被合并且顺序不变、无积压时逐条交付、真 UDP 突发往返。