環境與輸出均已脫敏:對端設備類型抽象為"匯流排設備"序號,不體現具體應用賽道;場景與排程參數為該類閘道的代表性描述,不指涉具體專案;設備型號、主機名稱為佔位符;SoC 型號為公開手冊資料,保留作定位依據。
TL;DR:閘道對 Windows 模擬器測 Modbus,TCP RTT 30–60ms、RTU 50–80ms 抖動。三步正交環回替換對端後確認:抖動來自測試對端,與被測板無關(在本次測試條件下)——被測板純軟體棧 0.69ms、實體網卡 1.02ms、串口 4.15ms(線傳佔比約七成)——單一事務佔端到端鏈路預算約 1%–15%(大幀口徑取上界),不構成阻滯項。對端側經變數干預鎖定台架實測下界 45–50ms:FTDI Latency Timer 從 16 改為 1 實測僅降 6.4ms(USB 排程節奏存在下界),模擬器應用層約 15ms 的回應節奏因 Windows 計時器按程序生效的語義保持黑盒。效能資料異常時,先審量測口徑與對端,再疑被測對象。
超出排程預算的 RTT
被測閘道基於 TI AM64x(2× Cortex-A53 @ 1.0GHz 級,Linux 6.12 PREEMPT_RT)。場景是一類常見的工業協議轉換部署:端到端鏈路為"上層排程系統 →(北向協議)→ 閘道 →(南向 Modbus)→ 多台匯流排設備",上層以百毫秒級週期輪詢控制,一條指令從下達到匯流排設備生效需在百毫秒內完成——約半個輪詢週期。閘道是鏈路的中間節點,兩側協議段的時延佔比必須足夠小,否則單是閘道就會吃掉鏈路預算的大頭;本次排查的目標,即確認閘道側時延是否低到不阻塞該預算。本文以 200ms 排程週期、1 主 4 從(RTU 側兩路 RS-485 匯流排各掛 2 台)為代表性排程參數與拓撲——參數為本文選取的測試基準,不指涉具體專案。用探針工具對 Windows 11 Pro 上的 ModbusTools Modbus Slave 模擬器(預設參數,未設回應延遲)做首輪時延測試,結果與排程預算直接衝突:
- Modbus-TCP:RTT 在 30–60ms 之間抖動
- Modbus-RTU:RTT 在 50–80ms 之間抖動
按單台 50ms 估算,單路匯流排兩台設備輪詢一遍就要消耗半個排程週期,四台集中到一條匯流排則直接佔滿;鏈路口徑更直接——單條指令 50–80ms 已佔掉百毫秒級預算的大半。若這些數字反映閘道的真實效能,鏈路時延要求無法達成,通信架構需要重新評估。但下結論之前,先確認一個問題:這 30ms 測的是誰?
先拆量測口徑:RTT 裡裝了什麼
翻探針原始碼,計時區間把 Connect() 整個包了進去:
const auto t_start = std::chrono::steady_clock::now();
const auto conn_res = transport.Connect(); // socket 建立 + TCP 三次握手
// ... Send / Receive ...
const auto t_end = std::chrono::steady_clock::now();
也就是說,每一次"RTT"都包含 socket 建立與完整的 TCP 三次握手;RTU 側同理,每輪都 open() 串口節點、tcsetattr 重置 termios、測完 close()。而生產環境的通信引擎是啟動時建連一次、整個運行期複用的長連線,串口句柄常駐——每個週期只有純 Send → Receive。
先修口徑再測:計時起點收縮到 Send() 緊鄰前一行,終點為接收完成後一行;TCP 改長連線常駐,RTU 串口打開一次常駐;循環模式輸出 min/max/avg 統計。改造順帶測出了建連開銷的實測值:[CONNECT] 1.29ms、[OPEN] 0.88ms——此前對握手與串口開關耗時的估算(分別為 20–30ms、5–10ms 量級)被實測證偽,建連環節的嫌疑就此排除。複測結果:
- TCP:平均 17.89ms(14.76–37.36)
- RTU:平均 52.18ms(34.40–67.27)
建連開銷摘掉了,數字仍然偏高,說明時延大頭在回應路徑上。接下來分兩步走:先換掉對端,證明板端清白;再回頭解釋對端為什麼慢。
三步正交隔離環回
自造對端:一個 0-sleep 極簡 Modbus Slave(收到 FC03/FC06 立即回包,單次記憶體業務耗時微秒級,開 TCP_NODELAY),交叉編譯上板。然後按"由內向外、逐層加介質"的順序做三步環回,每步只引入一個新變數:
| 步驟 | 拓撲 | 引入變數 | 預期 |
|---|---|---|---|
| 1 | 127.0.0.1 本機環回 | 無 | < 0.3ms |
| 2 | net5 ↔ net6 網路線對插 | 網卡控制器 + 匯流排 | 1–2.5ms |
| 3 | RS485_0 ↔ RS485_1 跳線對接 | UART + 收發器切換 | 8–15ms |
三個預期只有 Step 2 壓線命中,兩個 miss 同樣有資訊量:Step 1 的 <0.3ms 是按桌面級 CPU 估的,1GHz 低功耗核上幾次上下文切換加系統調用就是這個量級;Step 3 的 8–15ms 是按插入 t3.5 等待的常規從站估的,0-sleep mock 把這部分壓掉了——預期錯在哪一層,增量就歸因到哪一層。
Step 1:本機環回 —— 0.69ms
平均 0.69ms(0.47–1.28)。對端為 0-sleep 即時回應,處理路徑是純記憶體 PDU 解析加一次 send 系統調用,開銷在微秒級;RTT 主體為兩端核心 TCP/IP 協議棧路徑。軟體棧排除嫌疑。
Step 2:雙網卡網路線對插 —— 1.02ms
平均 1.02ms(0.78–1.64)。減去 Step 1 的軟體基數,AX88796B 網卡經 GPMC 匯流排的中斷與搬移只引入 0.33ms 硬體路徑增量。這一步踩了四個坑,都有記錄價值:
- 弱主機模型:同一台 Linux 的兩張網卡互發報文,核心發現目標是本機 IP,直接走
lo環回捷徑,電信號不經過網路線。標準解法是把對端網卡關進獨立網路命名空間,強制走實體口:ip netns add ns_eth6 ip link set net6 netns ns_eth6 ip netns exec ns_eth6 ip addr add 192.168.66.2/24 dev net6 ip netns exec ns_eth6 ip link set net6 up - 發起端沒 up + 跨網段:
net5預設 DOWN,且兩側配成不同 /24 網段後 SYN 匹配不到直連路由,被預設路由從調試網口漏到交換器上,報Connection timed out(探針 1 秒超時耗盡)。一根網路線沒有三層路由,兩側必須同網段,兩端網卡都要 up。 - PHY 自協商暫態:鏈路 up 後前兩個 ping 包丟失、第三包顯示 2049ms——這與 PHY 自協商 1.5–2 秒、再疊加 ping 把 ARP 排隊時間計入 RTT 的機理相符(推斷,未單獨隔離驗證),穩態複測即回落到 0.4ms。首包異常不等於鏈路故障。
- 網卡"消失":測試完
ip netns del後net6在主命名空間找不到——有程序仍駐留在被刪命名空間裡,核心會把它保留為匿名命名空間扣住網卡。用/proc比對命名空間 inode 定位佔用程序:for pid in $(ls /proc | grep '^[0-9]'); do if [ -e "/proc/$pid/ns/net" ] && \ [ "$(readlink /proc/1/ns/net)" != "$(readlink /proc/$pid/ns/net)" ]; then echo "佔用者: PID $pid ($(cat /proc/$pid/comm))"; kill -9 $pid fi done
Step 3:雙 RS-485 跳線對接 —— 4.15ms
兩路 RS-485 口均為板載原生 UART(核心 8250 驅動族接管),與 Windows 台架的 USB 轉接路徑形成對照。平均 4.15ms(3.97–4.44),抖動 0.47ms。物理量綱核算(115200 8N1,每位元組線上佔 10bit):
- 主站請求幀 8 位元組:80bit ÷ 115200 ≈ 0.69ms
- 從站回應幀 25 位元組:250bit ÷ 115200 ≈ 2.17ms
- 線傳合計 2.86ms
實測 4.15ms 減去線傳,附加開銷 1.29ms。這筆帳裡沒有協議幀間隔:對端原始碼為 0-sleep 即時回應,收齊完整請求幀後不插入 t3.5 等待、立即回包(規範對高於 19200 的鮑率建議取保守固定值 1.75ms——若存在,僅"線傳 + t3.5"就達 4.61ms,已超過實測均值,可獨立佐證)。1.29ms 為兩端 UART FIFO 中斷、驅動、收發器換向與程序排程的收發路徑開銷合計(減法歸帳,未逐項分解)。線傳 2.86ms 佔實測均值約七成;對 1.29ms 的收發路徑開銷,本文未做壓縮嘗試(FIFO 水位、中斷執行緒化等),不對其可壓縮性下結論。
資料總表
| 場景 | 介質 | 樣本 | 平均 RTT | 範圍 | 抖動(峰−峰) |
|---|---|---|---|---|---|
| 對照:Windows 模擬器 | TCP | 95 | 17.89ms | 14.76–37.36 | 22.60ms |
| 對照:Windows 模擬器 | USB-485 | 62 | 52.18ms | 34.40–67.27 | 32.87ms |
| Step 1 | localhost | 78 | 0.69ms | 0.47–1.28 | 0.81ms |
| Step 2 | net5 ↔ net6 | 28 | 1.02ms | 0.78–1.64 | 0.86ms |
| Step 3 | RS485_0 ↔ RS485_1 | 70 | 4.15ms | 3.97–4.44 | 0.47ms |
樣本量 28–95,統計口徑為 min/max/avg,未採集分位數;本文結論據此只用於均值與下界判斷,尾部時延留待現場聯調階段以更大樣本複核。
15.625 與 16:從機理假設到變數干預
板端清白已證,回頭解釋總表前兩行對照組:對端為什麼慢,慢的形態為什麼恰好是那樣。把兩個最小值與已知的系統常數做量綱比對,確實能對上。但"對得上"和"被證明"之間隔著變數干預——這一節記錄假設如何構造、干預怎麼做、以及干預結果如何反過來修正假設。
假設的構造:
- TCP 側:Windows 桌面系統預設計時器解析度約 15.625ms(1000ms / 64Hz);未提頻時,
Sleep、WM_TIMER這類等待會被量化到該粒度。若 GUI 模擬器的回應路徑包含此類等待(例如計時器驅動的收包輪詢),RTT 下限就會被抬到一個滴答附近。實測最小 14.76ms、平均 17.89ms、最大 37.36ms(約兩個滴答加處理開銷),與"週期約 15.6ms 的回應環節"這一模型相容。反過來說,阻塞 socket、IOCP、事件物件都能被網路完成立即喚醒,若模擬器走這類路徑,下限應在毫秒級(鏈路 ping<1ms)——實測下限 14.76ms 已經排除了"立即喚醒"類路徑,回應路徑上確實存在約 15ms 週期的環節。 - RTU 側:轉接晶片確認為 FTDI FT231X(VID
0x0403/ PID0x6015,驅動ftser2k.sysv2.12.36.20),其驅動 Latency Timer 預設 16ms——短幀從首位元組起算在晶片內等待超時後才上報主機(是超時 flush,不是"湊滿一個包";緩衝提前填滿則立即上報,本測試幀長遠小於該閾值)。疊加對端排程約 15.6ms,再加本測試幀配置的純線傳時間(FC03 讀 10 暫存器:請求 8B + 回應 25B ≈ 2.86ms),合計約 34.5ms,與實測最小值 34.40ms 僅差 0.2ms。
隨後完成的變數干預,結果分三類:
- FTDI Latency Timer 從 16 改為 1(裝置管理員 → 連接埠內容 → 連接埠設定 → 進階):RTU 均值從 51.89ms 降至 45.51ms——只降 6.38ms,遠小於單因素模型預期的約 15ms。機理被證實存在,但有效係數更小:Latency Timer 設為 1ms 不等於晶片真的按 1ms 上報,USB 批量傳輸的排程節奏給有效刷新間隔劃出了下界。單因素模型就此證偽,台架實測下界同時鎖定在 45–50ms——在本台架配置(FT231X 轉接晶片、ftser2k v2.12.36.20 驅動、預設參數模擬器)下,繼續調優 Windows 側未再觀察到邊際收益。
- 停用 USB LPM 與選擇性掛起:複測 51.42ms,與干預前同輪基線 51.89ms 的差異落在輪次間波動範圍內,無實質影響——RTT 仍在 45–50ms 台架帶內波動。
- 拓撲排除:轉接器經 Genesys GL850G Multi-TT Hub 接入,每個下行口有獨立 Transaction Translator,同口全速/低速設備競爭可排除。
系統時鐘粒度一項沒法這樣乾淨地判定。實測當前系統計時器週期已啟用為 1.0ms(可程式設計下限 0.5ms),看似能否定 15.625ms 量化假說;但 Windows 10 2004 起 timeBeginPeriod 改為按程序生效,系統級讀數不能保證模擬器程序內的等待原語同樣按 1ms 排程。判別實驗應當在模擬器程序上下文內提頻後再看下限是否落到毫秒級——該實驗無法從外部實施,約 15ms 節奏的具體來源(模擬器自身的計時器選擇,還是軟體內建的回應延遲)保持在應用層黑盒內。
ping 旁證的支援範圍也要劃清:Windows ping 閘道 <1ms 證明實體鏈路健康、時延產生在對端主機內部;反向閘道 ping Windows 100% 丟包只是 Windows 防火牆預設禁 ICMP 回顯,與 502 連接埠無關。它支撐"瓶頸在對端",不支撐任何具體時鐘機理。
另有一個獨立樣本可交叉驗證台架模型:同一對端上一次 FC06 控制寫實測 RTT 63ms、重試 0 次。拆解為:
- 線傳:請求幀與回顯幀各 8 位元組,約 1.38ms
- t3.5 幀間隔與收發器換向:按估計值 1.5–2.0ms(該對端實現未公開,取規範保守值)
- 板端開銷:按 Step 3 實測附加開銷(兩端合計 1.29ms)折半估取 0.5–0.7ms
- 剩餘約 59ms:落在 Windows 與 USB 轉接一側
後三項為估計或減法歸帳,非獨立驗證;t3.5 與板端兩項屬量級閉合而非精確歸因——多參數擬合一個觀測值不構成因果,恰是後文"可搬用的方法"第 2 條所警示的場景。Windows/USB 側佔比超過九成,與讀事務 45–50ms 的台架帶處於同一量級。
本節結論因此分兩層:探針讀數的大頭來自測試對端——這一點由前文三步環回的替換實驗證實;對端內部,USB 轉接緩衝一項經干預證實存在但收益有下界,台架實測下界 45–50ms;模擬器應用層約 15ms 的節奏保持黑盒。
兩條旁註:真實匯流排設備的控制器多為 MCU 裸機韌體,硬中斷回應,協議處理通常 1–3ms(行業經驗值,非本文實測),模擬器 15ms 量級的下限通常不會構成真實設備的同量級約束,但慢回應的真實從站同樣存在(如組態軟體編寫的 PLC、帶協議閘道的變頻器),本文未做驗證;把模擬器搬進 WSL2 或虛擬機器通常也無本質改善——Hyper-V 虛擬交換、VM-Exit 與宿主時鐘排程會引入新的時延層。
總成複驗:從單次事務到一個排程週期
Step 1–3 回答"一次事務多少錢",排程關心的是"一個週期夠不夠"。把自研排程引擎按代表性排程參數跑 10 秒有界總成:4 邏輯從站、200ms 輪詢週期、100ms 超時、典型遙測幀型(單一事務回應 137 位元組)、4 路齊備後原子提交。對端為板端 mock slave。RTU 側用單匯流排掛 4 個 Slave ID 時分輪轉——代表性部署為兩路 RS-485 各掛 2 台,單匯流排 4 從是比該部署嚴苛一倍的壓測拓撲,餘量結論對該部署只會更寬鬆;TCP 側因板載測試網口只有兩個,以 2 個實體端點承載 4 個 Unit ID(主站仍為一個,邏輯拓撲不變)。
結果:TCP 50/50 輪齊備提交,RTU 47–48/50 輪齊備提交;ALL_READY(引擎的從站線上狀態標誌,與逐輪齊備提交分屬兩個口徑)全程保持。兩個數字與機制一致:TCP 四通道並發互不影響;RTU 單匯流排時分,一次超時重試(100ms 超時等待,加一次約 14ms 的重試事務——單一事務耗時核算見下節)即佔去 200ms 週期的過半,連續兩次超時則超出整個週期——個別掉輪符合啟動對齊、寫注入或偶發重試這類一次性事件的特徵,具體觸發點未逐輪標註。從成績形態看,穩態吞吐不足可以排除:若每輪都超週期,成績會穩定在低位且不會出現滿額 50,而不是大多數輪滿額、偶爾 47–48。
按該幀型核算 RTU 一輪的物理下限:單一事務線傳 0.69 + 11.9 ≈ 12.6ms(請求 8B + 回應 137B),4 從站一輪 ≈ 50.3ms,佔 200ms 週期的 25%。這是純線傳下限;把 Step 3 小幀實測的 1.29ms 附加開銷按事務平移估算,單一事務約 14ms、一輪約 56ms——該開銷含 FIFO 中斷與換向等按事務計的成本,大幀下可能略增,精確值留待實際點表單包實測。即使按估算值,週期餘量仍超過 70%。而這還是嚴苛拓撲下的帳:代表性部署形態為兩路 RS-485 各掛 2 台,單路一輪線傳 ≈ 25.2ms(平移估算約 28ms),只佔 200ms 週期的 13–14%——Step 3 的"線傳為主"結論在系統層依然成立,對該形態餘量更寬。
回到最初的問題——30–80ms 高時延是不是 ARM RT-Linux 閘道側的問題——在本次測試條件下,證據鏈給出的答案是否定的:組件級(三步環回:雙網口 TCP 對發約 1ms、雙 RS-485 對發約 4ms)與系統級(200ms 週期總成滿輪運行)兩層均未觀測到閘道側瓶頸,高時延來自台架對端(Windows 主機、USB 轉接器與模擬軟體)。對照排查目標——閘道側時延是否阻塞端到端鏈路預算——按兩個口徑閉合:鏈路時延看單一事務,實測 1.02ms(TCP)/ 4.15ms(RTU 小幀)、大幀估算約 14ms,相對百毫秒級鏈路預算佔比約 1%–15%;排程吞吐看整輪,4 從站約 56ms、200ms 週期餘量 70% 以上。兩個口徑下閘道側均不構成阻滯項。結論邊界需註明:隔離與總成的對端均為 Mock,測試為空載單一事務口徑、總成為 10 秒有界視窗,未覆蓋北向並發、長時間運行等更接近現場的負載形態;北向協議段(上層系統到閘道)的時延特性不在本文量測範圍內。通信基礎設施(南向段)在此基線下不再是阻滯項。
(計數口徑教訓:這套總成的早期統計曾把 1ms 排程 tick 誤計為事務輪次,產出過虛高約兩個數量級的吞吐數字;修正後的口徑是"4 路齊備原子提交"。先定義"一次"是什麼,再談數字——與量測口徑問題同構。)
結論與工程產出
- 歸因結論:首輪 30–60ms(TCP)/ 50–80ms(RTU)抖動與口徑修正後的複測結果,均可歸因於測試對端——替換對端後各層抖動均收縮到 1ms 以內(峰−峰),被測板在各層實驗中均未呈現瓶頸,串口鏈路約七成為線傳物理耗時。對端內部經變數干預確認:USB 轉接 Latency Timer(16→1,均值降 6.4ms)收益存在實測下界,台架實測下界 45–50ms;模擬器應用層約 15ms 的回應節奏保持黑盒。
- 超時閾值參考基線:Modbus-TCP 建議 15–25ms、Modbus-RTU 建議 30–50ms。裕度口徑需明示——以閘道自身開銷為分母(TCP 1.02ms / RTU 4.15ms)時為 15–25 倍 / 7–12 倍;但超時須覆蓋對端回應,計入真實從站處理 1–3ms 與 RTU 側 t3.5(約 1.75ms)後,端到端事務的實際裕度大致減半(TCP 約 4–12 倍、RTU 約 3–7 倍)。超時閾值不宜放大到數百毫秒量級——單點設備斷線需要在數十毫秒級被排程循環識別並切除。
- 基線使用約束:其一,以真實從站回應顯著快於 Windows 模擬器為前提;其二,RTU 30–50ms 低於 Windows 台架實測 RTT(45–80ms),聯調階段若仍以 Windows 模擬器為對端,應沿用總成的 100ms 配置。該基線較 100ms 保守配置收緊,落地前需經現場聯調驗證。
- 排程預算:按比代表性週期(200ms)嚴苛一倍的 100ms 口徑核算(總成實際按 200ms 運行),單一事務佔比 TCP 1.02% / RTU 4.15%;多從站一輪物理下限核算見上節——嚴苛壓測拓撲(單匯流排 4 從站)一輪約 50.3ms(200ms 週期餘量 70% 以上),代表性部署(兩路匯流排各掛 2 台)單路約 25.2ms。
- 如果不得不用 Windows 模擬器做功能聯調(本台架轉接晶片已確認為 FTDI FT231X;CH340/CP2102 無此設定項):裝置管理員 → 連接埠內容 → 連接埠設定 → 進階 → Latency Timer 從 16 改為 1。本台架實測均值由此下降約 6.4ms(51.89→45.51),收益存在 USB 排程下界,不要按理論值 15ms 預期。功能聯調可用,但不宜作為效能評估的對端——至少在本台架(預設參數、未設回應延遲)的實測條件下如此。
可搬用的方法
- 量測口徑先於量測資料。拿到一個效能數字,先問計時區間裡裝了什麼:建連握手?設備 open/close?對端的排程週期?口徑不定義,資料之間不可比。
- 量綱吻合產出候選解釋,變數干預才產出判定。15.625ms、16ms 這類系統常數能把假設從憑空猜測升級為候選解釋——本文的最小值比對排除了"立即喚醒"類路徑;但多個可調參數擬合一個觀測值不構成因果。判別方法是改一個變數(提頻、改 Latency Timer、換轉接晶片),看最小值是否隨之移動。干預結果可以是非理想的——本文 Latency Timer 從 16 改為 1 只換來 6.4ms 降幅,單因素模型即被證偽;這同樣是有效資訊,它把排查指向下一個物理下界,而不是允許在原假設上繼續加參數。
- 變數正交隔離。懷疑全鏈路時,從純軟體到物理層逐層加介質:localhost 定軟體基數,實體直連測硬體增量,匯流排對接分離線傳與附加開銷。每一層的增量都可單獨歸因。
- 模擬器不等於被測對象。GUI 模擬器自帶訊息泵與系統時鐘抖動,適合驗功能,不適合評效能。效能驗證用 0-sleep 極簡對端,把對端開銷壓到可忽略。
- 同機雙網卡測真實體鏈路,netns 是標準手段。否則弱主機模型會讓報文在核心裡走捷徑,測不到實體鏈路。
在嵌入式 Linux 上做同類匯流排時延驗證時,這套"口徑修正 → 量綱比對與變數干預 → 三步環回"的流程和文中命令可以直接搬用。