軟中斷網卡處理&Linux高性能外部設備處理機制

Jack:Linux外部設備的性能如何才能高呢?

我:你爲什麼希望外部設備的性能好呢?

Jack:典型的說,外部設備如磁盤、網卡都需要非常好的性能。磁盤設備處理性能好,才能承載數據庫系統。網卡性能好,才能承載高性能server(數據庫或者web server)。

我:那你覺得用什麼樣的方式處理這兩個外部設備,它的性能會好呢?

Jack:外部設備要好,當然應該採用中斷方式,這是性能最高的。

我:你錯了。外部設備與CPU的交互方式,最快的是DMA。但是,DMA方式會使外部設備的控制器獨佔PCI總線,從而CPU無法與外部設備進行交互——這對通用型操作系統來說,是很難接受的。所以DMA方式,在Linux內核裏使用得很少。Linux筆記是一個通用型操作系統,而非專用型嵌入式操作系統。

Jack:說了這麼多,還是要用中斷纔行。

我:是的。但是中斷僅僅是最基本的方式。使用中斷這種外部設備處理方式,有兩個硬傷需要面對:

1、丟失中斷問題:在中斷響應代碼裏,一般都會調用cli()宏定義關閉中斷,當中斷完成之後,再調用sti()宏定義打開中斷。如果中斷響應代碼執行時間比較長(毫秒級別),那麼在這段時間內,中斷都無法響應——這對於一個server操作系統來說,是無法接受的。

2、SMP均衡問題:在SMP下,常用的中斷默認只會落到CPU0上去,其餘的CPU無法處理中斷,這對整個操作系統的可擴展性來說,是致命的。

這兩個問題對所有外部設備都適用,如果外部設備對性能要求非常之高,那麼,這兩個問題一定要解決。

Jack:常見的對性能要求非常之高的外部設備有哪些呢?

我:最常見的是網卡設備和磁盤設備。其中,對於網卡設備而言,這兩個問題尤其棘手。

Jack:對於網卡設備而言,這兩個問題是怎麼解決的呢?

我:對於中斷丟失的問題,Linux內核早期採用了BH的機制。而對於SMP的問題,Linux內核至今沒有完美的解決辦法。當然,這並不是說就沒有解決的辦法,只是有些互聯網公司沒把核心技術開源出來而已。

Jack:BH機制是怎麼回事呢?

我:BH是bottom half的縮寫,但是BH已經是一個專有名詞,代表最早的Linux內核的bottom half機制,而bottom half是一個通用名詞。Linux內核從程序猿的角度把中斷響應程序分爲兩部分——上半部、下半部。上半部做標記功能用,下半部根據上半部的標記幹活。上半部與下半部的本質區別是,上半部可以關閉中斷,而下半部不能關閉中斷。所以,bottom half的概念,完全是hacker意淫出來的,並非是CPU層面的概念。

Jack:那BH這種意淫出來的機制的好處在哪裏呢?

我:這種機制的優點在於解決了第一個問題——丟失中斷。通過把上半部極致地濃縮,可以最大限度地減少關閉中斷的時間,從而減少中斷丟失——沒有絕對的不丟失中斷,只能最大限度地減少中斷丟失。

Jack:那BH機制的缺點是什麼呢?

我:這個問題問得很好,不僅問了有點是什麼,同時問了缺點是什麼。兩個點你都弄清楚了,差不多就高潮了。

Jack:去死吧。

我:BH機制的缺點在於無法解決第二個問題。就是BH機制在SMP下,表現得太齪逼了。

Jack:仔細一點呢?

我:BH硬編碼定義了32類Bottom half,這32類botton half在同一時刻只能執行其中一種,即便是在SMP環境下,也是如此。所以,BH機制是絕對的串行化,而沒有任何併發能力。

Jack:絕對的串行化也很好,實現非常簡單,只是無法發揮多核的優勢。

我:這種說法等於上館子喫飯只喝水不點菜、不叫飯,因爲這樣省錢。但是這樣的做法,是SB的。

Jack:那麼Linux在處理外部設備的性能問題上,如何解決SMP的呢?

我:在Linux2.6版本內核裏,提供了3種成熟的方法來解決外設與SMP配合的問題:軟中斷、tasklet、工作隊列。其中,軟中斷是一種全新的機制,具備在SMP下軟中斷類型間的併發甚至是同種軟中斷內的併發能力。tasklet建立在軟中斷之上,是軟中斷的一種特例,相比於軟中斷,tasklet不具備同種軟中斷內的併發能力。對於除磁盤設備、網卡設備而言,幾乎所有的外部設備用tasklet就夠了。只有極少數的外部設備需要自己定製軟中斷。當然了,軟中斷的定製不是那麼簡單的。且不說需要對軟中斷的原理、實現代碼非常熟悉。更難的是,需要自己實現軟中斷在SMP下,同種軟中斷內部間的互斥與同步。如果採用簡單粗暴的spinlock,那麼軟中斷在性能上就已經失去意義。而採用別的數據結構實現數據同步與互斥,又具備相當大的難度,所以,即便是Linux內核的官方版本,對這個問題也是極爲頭疼。至於第三種——工作隊列。這種機制與前兩種機制的最大差別在於,這種機制的bottom half會通過內核線程進入休眠,之後被喚醒。這裏有兩個難點,第一點是,休眠會引起上下文切換(context switch),對性能具有極大的殺傷。第二點是,Linux內核作者是非常反對user創建內核線程的——原因不言而喻,Linux內核是內核作者寫好對外提供服務的,你一來就動大手術,把內核改造了,加了線程,誰能保證在某種情況下不出現問題呢?出了問題之後,會找誰解決呢?一般人當然首先先到內核作者。可是,當你找到內核作者的時候,情形好比是你把一臺剛買的筆記本用螺絲刀打開過了,還下了幾個零件,然後電腦壞了,你對售後服務說“我的電腦壞了,你幫我修理下。”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章