PTT評價

[心得] RSS+RPS+RFS優化NIC到播放軟體的資料路徑

看板Audiophile標題[心得] RSS+RPS+RFS優化NIC到播放軟體的資料路徑作者
elguapo
(HPHT Synthesized)
時間推噓 1 推:1 噓:0 →:0

繼前一篇 #1cWInSDW 分享第三層交換器優先權設定之後,這篇來分享一旦資料進入
網卡後,如何再優化 Linux 作業系統內部的資料流;這裡一樣是只探討優化手法,
不討論音質的改變(YMMV...)

關於 Receive Side Scaling, RSS 相關說明文件在此:
https://tinyurl.com/5d9zuace

RSS 也算是一個古老的存在了,許多高負載伺服器也都會運用這個功能去分攤/處理
所接收的資料流。其運作原理是根據來源地址、來源埠、目的位址及目的埠,送入
一個叫 Toeplitz(預設)的矩陣去換算出 hash 值,再用這個 hash 去對應的接受
儲列。例如,我的 HQPlayer Embedded 主機接收 NFS 的資料,根據相關地址和埠,
會交給儲列 8 來處理:
https://imgur.com/pr9YHN4.jpg

管理者即能用這個機制,用 ethtool 去分配特定服務給特定軟體所在的 CPU 接收
資料,來減少資料延遲。

在音訊網路裡面,能想到的大概是 Roon -> RoonBridge 或是 Roon -> HQPlayer
-> NAA 這樣的傳遞接收路徑;RSS 的設定方式大同小異,這裡就用我的 NAA <->
Ravenna bridge 做個例子,好處是內核設定的改動,都能反映在 Ravenna 器材上
的接收狀態。

我的 NAA 是 Intel Atom x7425e 四核心的單板電腦,跑 Ubuntu 實時核心,有特別
隔離一顆 CPU 核心做其他的事情。開完機之後我們可以看到由於 CPU 為四核心,
RxTx 儲列會有四個(RxTx-0~RxTx-3),但因為我把第四個 CPU 核心獨立出來不受
干擾,因此儲列的 IRQ 會自動轉分佈在前三個 CPU 核心。
https://imgur.com/WIDo1Xp.jpg


但 RSS indirection table 的數值仍是指向四個 Rx 儲列,這表示仍有一個 CPU
核心要處理兩個 Rx 儲列:
https://imgur.com/x3pAL70.jpg

如果不去變動 RSS 等設定的話,NAA 交給 Ravenna 的資料,Ravenna 接收端會呈現
一些鋸齒狀:
https://imgur.com/MMe9OOY.jpg
這些鋸齒狀都還是在容許範圍內,因此不會造成音訊中斷/爆音/破音/雜音等問題,
只是看起來不舒服。

不知為何 x7425e 並未支援 hash key,手上工具算不出來資料流會走哪個儲列,
因此策略上我個人是採取「機會均等」,讓 enp1s0 這個負責 NAA 的網口所接收的
資料平均分給三個 Rx 儲列,指令:

ethtool -X enp1s0 equal 3

(enp1s0 是我的網口名稱,請自行代入自己機器抓出的網口名稱。)

這樣就能把 RSS indirection table 強制平均分配到三個 Rx 儲列:
https://imgur.com/cjcLxHo.jpg


接下來再用 Receive Packet Steering, RPS 技巧,將 Rx 的儲列重新順給 CPU 第
0, 1, 2 核上,指令:

echo 1 > /sys/class/net/enp1s0/queues/rx-0/rps_cpus
echo 2 > /sys/class/net/enp1s0/queues/rx-1/rps_cpus
echo 4 > /sys/class/net/enp1s0/queues/rx-2/rps_cpus

1,2,4 是二進位遮罩轉為十進位數值,二進位最右邊是第一顆 CPU 核心,因此我
指定某個 Rx 儲列由 CPU 第三顆核心處理的話,二進位遮罩是 0100,換算十進位
是 4,以此類推。

Rx 儲列安排好之後,當然最理想是 IRQ 也一併和 Rx 儲列調整,前面截圖已知
RxTx-0, RxTx-1, RxTx-2 的 IRQ 分別是 128, 129, 130,我們就可以指定 IRQ
給相對的 CPU 核心:

echo 0 > /proc/irq/128/smp_affinity_list
echo 1 > /proc/irq/129/smp_affinity_list
echo 2 > /proc/irq/130/smp_affinity_list

(當然在做這個設定之前,要將 irqbalance 守護程式整個關掉。)

截圖呈現三個 RxTx 儲列的 IRQ 分別交給 CPU 0, 1, 2
https://imgur.com/QETjXby.jpg


為了配合這個 Rx 儲列硬平均,我也指定 networkaudiod 這個 daemon 跑在負責這
三個儲列的 CPU 核心上(networkaudiod 的主體 thread 會在這三個 CPU 核心上
隨機跑動)。

不過這也還是單位時間內 33% 機率資料流會被 networkaudiod 的主 thread 吃到,
因此還可以再用 Receive Flow Steering, RPS 來輔助資料流導向的命中率,這個
部分因為服務單純,因此 flow table 大小我並沒有設很大,這部分就看個人的
需求而定:

echo 8192 > /proc/sys/net/core/rps_sock_flow_entries

其他 Rx 儲列的 flow table 必須小於主 table size,我是設定 1024:

echo 1024 > /sys/class/net/enp1s0/queues/rx-0/rps_flow_cnt
echo 1024 > /sys/class/net/enp1s0/queues/rx-1/rps_flow_cnt
echo 1024 > /sys/class/net/enp1s0/queues/rx-2/rps_flow_cnt

NAA 經過 RSS + RPS + RFS 的調整之後,Ravenna 器材接收端變平順了些:
https://imgur.com/wZia5OZ.jpg


若您的 endpoint 是小電腦,不妨試著調整看看,或許會有驚喜 :-)

(以上的調整是採 run-time 方式調整,若會寫 shell script 就能省很多事,但
這裡就不是主題範圍了...)

--

※ PTT 留言評論
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.163.96.58 (臺灣)
PTT 網址
※ 編輯: elguapo (118.163.96.58 臺灣), 07/07/2024 14:34:39

iitze07/07 16:00推專業