首頁 > 軟體

Linux核心3.11的socket busy poll機制避免睡眠切換

2020-06-16 17:57:52

Linux的網路協定棧非常獨立,上下通過兩個介面分別和使用者態以及裝置相連,也可以看作是北向和南向介面...北向通過socket介面,南向通過qdisc介面(你可以認為是上層的netdev queue,對於接收介面,NAPI的poll佇列則是另一個例子),不管是socket還是qdisc,都是基於佇列來管理的,也就是說,三個部分是獨立的,socket只能看到讀寫佇列,而看不到協定棧本身,socket在讀一個資料的時候,它取的是佇列裡面的資料,至於說這個資料是誰放進去的,它並不知道,是不是協定棧放進去的,它也不必驗證。

socket隔離了使用者進程和協定棧,RX/TX queue隔離了協定棧和裝置驅動。

這種隔離方式給程式設計和設計帶來了簡便,然而卻不利於效能。

Linux的RPS設計,旨在讓一個CPU既處理封包的協定棧接收流程(軟中斷核心執行緒上下文,或者任意上下文的軟中斷處理),又執行使用者態處理該封包的進程。我說這種設計有利也有弊,如果僅僅是旨在提高cache利用率,那麼這種設計是對的,但是有沒有想過別的情況,如果一個CPU在NET RX軟中斷處理的最後將一個skb推到了一個socket佇列,並試圖喚醒等待進程,那麼它下一步該幹些什麼呢?實際上它下一步應該返回裝置,繼續去poll下一個skb,然而RPS的設計不是這樣,RPS的設計旨在希望讓該CPU繼續處理使用者態進程....這就必然要進行一次進程切換以及使用者/核心態的切換,雖然伺服器的CPU cache利用率提高了,但是協定棧處理相關的CPU cache利用率反而降低了。事實上,CPU cache是否在進程切換以及使用者/核心態切換後重新整理,這個是體系結構相關的,並不是說所有的體系結構都能帶來好的結果。

必須做進一步的測試。

我覺得最好的辦法就是使用者進程和核心的NET RX軟中斷處在不同的CPU核心上,然而這兩個CPU核心共用二級cache或者三級cache。

...

Linux核心隨之發展出了更好的方案,那就是突破上述的獨立三大部分,讓socket直接深入到裝置層直接poll skb!!注意,這是一個poll操作,並不是讓socket直接處理協定棧流程。socket直接poll的意思是說,socket在佇列中沒有讀到封包的時候,並不是睡眠,然後等待NET RX核心執行緒將封包放入佇列後將其喚醒,而是直接去問裝置:現在有封包嗎?如果有,我直接帶走它們去協定棧,而不需要你送它們去了。這是一種“拉”的方式,而不是以往的那種“推”的方式,拉和推的區別在於,對於接收者,拉是同一個實體,是主動的,而推則是被動的。

這就解決了RPS試圖解決卻又沒有完美解決的問題。這種機制叫做busy poll。

RPS試圖讓軟中斷處理完封包後,切換到使用者進程,此時軟中斷將間歇,然後封包中斷後又要切回來...busy poll就不是這樣,它直接繞過了軟中斷這個執行體,直接靠socket自身所在的執行體來主動拉取封包進行處理。避免了大量的任務交接導致的切換問題。

我不曉得對於轉發的情況,是否也能採用busy poll的方式來提高效能,這需要測試。以上的闡述只是理想情況,真實情況是,socket可能替別的socket從裝置拉取了一個封包,甚至這個封包只是轉發的,不與任何socket關聯...因為封包只有經過標準的路由以及四層處理後,才能和一個具體socket關聯,在裝置驅動層,指望找到這個關聯是徒勞且無望的!不管怎麼說,控制權在使用者自己手中,憑概率來講,如果你的裝置中大量的封包都是轉發包,就不要開啟這個功能,如果你的進程擁有少量的socket處理大量的封包,那就開啟它,不管怎樣,這只是一個用法和設定的問題,何時開啟,以及份額設定多少,需要一個事前取樣的過程。

本文永久更新連結地址http://www.linuxidc.com/Linux/2015-07/119592.htm


IT145.com E-mail:sddin#qq.com