0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入理解Linux RCU:經(jīng)典RCU實(shí)現(xiàn)概要

Linux閱碼場(chǎng) ? 來源:未知 ? 作者:李倩 ? 2018-05-10 09:08 ? 次閱讀

1、準(zhǔn)備工作

本文基于linux 2.6.32-rc7版本的源碼, 因此請(qǐng)準(zhǔn)備一份linux2.6.32-rc7代碼。建議用如下兩種方法獲取源代碼:

1、直接在linux.org上面下載源碼包。

2、使用git從linux-next拉取最新代碼,然后使用git checkout -b linux-2.6.32-rc7 v2.6.32-rc7檢出2.6.32-rc7版本的源碼。

2、概述

雖然Linux更早版本中的經(jīng)典RCU,其讀端原語擁有出色的性能和擴(kuò)展性,但是寫端原語則需要判斷預(yù)先存在的讀端臨界區(qū)在什么時(shí)候完成,它僅僅被設(shè)計(jì)用于數(shù)十個(gè)CPU的系統(tǒng)。經(jīng)典RCU的實(shí)現(xiàn),要求在每個(gè)優(yōu)雅周期內(nèi),每個(gè)CPU必須獲取一個(gè)全局鎖,這使得它們的擴(kuò)展性受到了限制。雖然在實(shí)際生產(chǎn)系統(tǒng)中,經(jīng)典RCU可以運(yùn)行在幾百個(gè)CPU的系統(tǒng)中,甚至能夠比較困難的使用到上千個(gè) CPU的系統(tǒng)中,但是大型多核系統(tǒng)仍然需要更好的擴(kuò)展性。

另外,經(jīng)典RCU有一個(gè)不是最優(yōu)的dynticks 接口,導(dǎo)致經(jīng)典RCU在每一個(gè)優(yōu)雅周期都要喚醒每一個(gè)CPU,即使這些CPU處于idle狀態(tài)。我們考慮一個(gè)16核的系統(tǒng),它只有四個(gè)CPU比較忙,其他CPU的負(fù)載都很輕。理想情況下,余下12個(gè)CPU可以一直處于深度睡眠模式以節(jié)約能源。然而不幸的是,如果四個(gè)忙的CPU頻繁的執(zhí)行RCU更新,這12個(gè)空閑CPU會(huì)被周期性的喚醒,浪費(fèi)了重要的能源。因此,對(duì)于經(jīng)典RCU的任何優(yōu)化,都應(yīng)當(dāng)讓這些睡眠狀態(tài)的CPU繼續(xù)處于睡眠狀態(tài)。

經(jīng)典RCU和分級(jí)RCU實(shí)現(xiàn)都有和經(jīng)典RCU相同的語義和API。但是,原有的實(shí)現(xiàn)被稱為“經(jīng)典RCU”,新實(shí)現(xiàn)被稱為“分級(jí)RCU”。

2.1.RCU基礎(chǔ)回顧

從最基本的方面來說,RCU 是一種等待事務(wù)完成的方法。當(dāng)然,要等待事務(wù)完成,還存在很多其他方法,包括引用計(jì)數(shù)、讀寫鎖、事件等等。RCU的一個(gè)大的優(yōu)勢(shì)是可以同時(shí)等待20,000個(gè)不同的事件,而不必具體的跟蹤其中每一個(gè)事件,并且不用擔(dān)心性能被降低,以及擴(kuò)展性被限制,也不用擔(dān)心復(fù)雜的死鎖情況和內(nèi)存泄漏的危險(xiǎn)。

在RCU中,被等待的事件被稱為“RCU 讀端臨界區(qū)”。RCU讀端臨界區(qū)以rcu_read_lock()原語開始,以相應(yīng)的rcu_read_unlock() 原語結(jié)束。RCU讀端臨界區(qū)可以嵌套,也可以包含相當(dāng)多的代碼,只要這些代碼不阻塞或者睡眠(當(dāng)然,這是針對(duì)經(jīng)典RCU來說的。有一種特殊的名為SRCU的可睡眠RCU,它允許在SRCU讀端臨界區(qū)中進(jìn)行短期睡眠)。如果您遵從這些約束,您可以使用RCU來等待任何代碼片段完成。

RCU通過間接的確定其他事務(wù)何時(shí)完成來實(shí)現(xiàn)這一點(diǎn)。但是,請(qǐng)注意:在特定的優(yōu)雅周期之后開始的RCU 讀端臨界區(qū)能夠、也必然會(huì)延長(zhǎng)優(yōu)雅周期的結(jié)束點(diǎn)。

2.2.經(jīng)典RCU實(shí)現(xiàn)概要

經(jīng)典RCU實(shí)現(xiàn)的關(guān)鍵原理是:經(jīng)典RCU 讀端臨界區(qū)限制其中的內(nèi)核代碼不允許阻塞。這意味著在任意時(shí)刻,一個(gè)特定的CPU只要看起來處于阻塞狀態(tài)、IDLE循環(huán)、或者離開了內(nèi)核后,我們就知道所有RCU讀端臨界區(qū)已經(jīng)完成。這些狀態(tài)被稱為“靜止?fàn)顟B(tài)”,當(dāng)每一個(gè)CPU已經(jīng)經(jīng)歷過至少一次靜止?fàn)顟B(tài)時(shí),RCU優(yōu)雅周期結(jié)束。

經(jīng)典RCU最重要的數(shù)據(jù)結(jié)構(gòu)是rcu_ctrlblk,它包含了->cpumask字段,每一個(gè)CPU在該字段中包含一位,如上圖所示。當(dāng)每一個(gè)優(yōu)雅周期開始時(shí),每一個(gè) CPU相應(yīng)的位被設(shè)置為1,每一個(gè)CPU經(jīng)過一次靜止?fàn)顟B(tài)時(shí),必須清除相應(yīng)的位。由于多個(gè)CPU可能希望同時(shí)清除它們的位,這將破壞->cpumask 字段,因此使用了一個(gè)->lock自旋鎖來保護(hù)->cpumask。不幸的是,當(dāng)超過幾千個(gè)CPU時(shí),這個(gè)自旋鎖會(huì)遇到嚴(yán)重的競(jìng)爭(zhēng)狀態(tài)。更糟糕的是,事實(shí)上所有CPU必須清除它們的位,意味著在一個(gè)優(yōu)雅周期內(nèi),CPU不允許一直睡眠。這削弱了LINUX節(jié)能的能力。

2.3.RCU迫切要解決的問題

實(shí)時(shí)RCU迫切要解決的問題列表如下:

1. 延遲銷毀。這樣,直到所有已經(jīng)預(yù)先存在的RCU讀端臨界區(qū)已經(jīng)完成,一個(gè)RCU優(yōu)雅周期才能結(jié)束。

2. 可靠性,這樣RCU支持24x7運(yùn)行。

3. 可以在IRQ處理函數(shù)中調(diào)用。

4. 包含內(nèi)存標(biāo)記,這樣,如果有很多回調(diào)過程,這種機(jī)制將加快結(jié)束優(yōu)雅周期。

5. 獨(dú)立的內(nèi)存塊,這樣RCU能夠基于可信的內(nèi)存分配器進(jìn)行工作。

6. synchronization-free的讀端,這樣允許通常的非原子指令操作于CPU(或者任務(wù))的本地內(nèi)存。

7. 無條件的read-to-write提升,在LINUX內(nèi)核中,有幾個(gè)地方需要這樣使用。

8. 兼容的API。

9. 搶占RCU讀端臨界區(qū)的要求可以被去掉。

10. 極低的RCU內(nèi)部鎖的競(jìng)爭(zhēng),從而帶來極大的擴(kuò)展性。RCU必須支持至少1,024個(gè)CPU,最好是至少4,096個(gè)CPU。

11. 節(jié)能:RCU必須能夠避免喚醒低電壓狀態(tài)的dynticks-idle CPU,但是仍然能夠判斷當(dāng)前的優(yōu)雅周期何時(shí)結(jié)束。這已經(jīng)在實(shí)時(shí)RCU中實(shí)現(xiàn),但是需要大大的簡(jiǎn)化。

12. RCU讀端臨界區(qū)必須允許在NMI處理函數(shù)中使用,就如在中斷處理函數(shù)中一樣。

13. RCU必須很好的管理不停的CPU熱插撥操作。

14. 必須能夠等待所有事先注冊(cè)的RCU回調(diào)完成,雖然這已經(jīng)以rcu_barrier()的形式提供。

15. 檢測(cè)失去響應(yīng)的CPU是值得的,以幫助診斷RCU和死循環(huán)BUG及硬件錯(cuò)誤,這能夠防止RCU優(yōu)雅周期不能結(jié)束的情況。

16. 加快RCU優(yōu)雅周期是值得的,這樣RCU優(yōu)雅周期能夠強(qiáng)制在數(shù)百微秒內(nèi)完成。但是,這樣的操作預(yù)期會(huì)帶來嚴(yán)重的CPU負(fù)載。

最急迫的首要需求是:可擴(kuò)展性。因此需要減少RCU的內(nèi)部鎖。

2.4.邁向可擴(kuò)展RCU實(shí)現(xiàn)

減少鎖競(jìng)爭(zhēng)的一個(gè)有效方法是創(chuàng)建一個(gè)分級(jí)結(jié)構(gòu),如上圖所示。在此,四個(gè)rcu_node 結(jié)構(gòu)中的每一個(gè)都有各自的鎖,這樣只有 CPU 0 和 1 會(huì)獲取最左邊的 rcu_node的鎖, CPU 2 和 3 會(huì)獲取中間的rcu_node的鎖,CPU 4和5會(huì)獲取右邊的rcu_node的鎖。在任一個(gè)優(yōu)雅周期期間,僅僅某一個(gè)CPU節(jié)點(diǎn)會(huì)訪問rcu_node 結(jié)構(gòu)的上一層的rcu_node。也就是說,在上圖中,每一對(duì)CPU(它們處于同一個(gè)CPU節(jié)點(diǎn))中,最后一個(gè)記錄靜止?fàn)顟B(tài)的CPU才會(huì)訪問上一層的rcu_node。

這樣做的最終結(jié)果,是減少了鎖的競(jìng)爭(zhēng)。在經(jīng)典RCU中,6個(gè)CPU在每一個(gè)優(yōu)雅周期內(nèi)競(jìng)爭(zhēng)同一個(gè)全局鎖,在上圖中,僅僅是三個(gè)節(jié)點(diǎn)競(jìng)爭(zhēng)最上層的rcu_node鎖 (降低了50%)。

rcu_node結(jié)構(gòu)樹被嵌入到rcu_state 結(jié)構(gòu)的一個(gè)線性數(shù)組,樹根是結(jié)點(diǎn)0,如上圖。它是一個(gè)8-CPU的、三層分級(jí)結(jié)構(gòu)的系統(tǒng)。 每一個(gè)箭頭將一個(gè)rcu_node 結(jié)構(gòu)鏈接到它的父結(jié)點(diǎn),這對(duì)應(yīng)著rcu_node結(jié)構(gòu)的->parent 字段。每一個(gè)rcu_node都標(biāo)示了它所覆蓋的CPU范圍,這樣根結(jié)點(diǎn)覆蓋了所有CPU,每一個(gè)二級(jí)結(jié)點(diǎn)覆蓋了一半的CPU,每一個(gè)葉子結(jié)點(diǎn)覆蓋了兩個(gè) CPU。這個(gè)數(shù)組在編譯時(shí)基于NR_CPUS的值靜態(tài)分配。

上圖顯示了如何檢測(cè)優(yōu)雅周期。在第一個(gè)圖中,沒有CPU經(jīng)過靜止?fàn)顟B(tài),并用紅塊標(biāo)示。假設(shè)所有6個(gè)CPU試圖同時(shí)告訴RCU,它們已經(jīng)經(jīng)過一個(gè)靜止?fàn)顟B(tài)。那么,在每一對(duì)CPU中,僅僅其中某一個(gè)CPU能夠獲得底層rcu_node結(jié)構(gòu)的鎖。第二個(gè)圖中,假設(shè)CPU0、3、5比較幸運(yùn)的獲得了底層rcu_node結(jié)構(gòu)的鎖,在圖中標(biāo)識(shí)為綠色塊。一旦這些幸運(yùn)的CPU結(jié)束了,那么其他CPU將獲得鎖,如圖3所示。這三個(gè)CPU中,每一個(gè)CPU將會(huì)發(fā)現(xiàn)它們是組內(nèi)最后一個(gè)CPU,因此所有三個(gè)CPU嘗試移到上層rcu_node。此時(shí),僅僅其中一個(gè)能獲得上層rcu_node 鎖。我們假設(shè)CPU1、2、4依次獲得了鎖,則第4、5、6圖顯示了相應(yīng)的狀態(tài)。最后,第6圖顯示了所有CPU已經(jīng)經(jīng)過一次靜止?fàn)顟B(tài),因此優(yōu)雅周期結(jié)束。

在上面的順序中,沒有超過3個(gè)CPU為同一個(gè)鎖產(chǎn)生競(jìng)爭(zhēng),與經(jīng)典RCU進(jìn)行對(duì)比,我們會(huì)高興的發(fā)現(xiàn),經(jīng)典RCU中,所有6個(gè)CPU都可能沖突。但是,對(duì)更多的CPU來說,可以再顯著的減少鎖之間的沖突。考慮有64個(gè)底層結(jié)構(gòu)及64*64=4,096 CPU的分組結(jié)構(gòu),如圖上圖。

在此,每一個(gè)底層rcu_node 結(jié)構(gòu)的鎖被64個(gè)CPU申請(qǐng),將從經(jīng)典RCU的4096個(gè)CPU競(jìng)爭(zhēng)一個(gè)單一的鎖降為64個(gè)CPU競(jìng)爭(zhēng)一個(gè)鎖。在一個(gè)特定的優(yōu)雅周期期間,僅僅一個(gè)底層rcu_node 中的某一個(gè)CPU會(huì)申請(qǐng)上級(jí)rcu_node 的鎖。這樣,與經(jīng)典RCU相比,減少了64倍的鎖競(jìng)爭(zhēng)。

2.5.邁向不成熟的RCU實(shí)現(xiàn)

正如較早前提示的一樣,這些努力的一個(gè)重要目的是使一個(gè)處于睡眠狀態(tài)的CPU保持它的睡眠狀態(tài),以節(jié)約能源。與之相對(duì)的是,經(jīng)典RCU至少會(huì)在一個(gè)優(yōu)雅周期內(nèi)喚醒每一個(gè)處于睡眠狀態(tài)的CPU。當(dāng)其他大多數(shù)CPU都處于空閑狀態(tài)時(shí),這些個(gè)別的CPU進(jìn)行rcu寫操作,會(huì)使得這種處理方法不是最優(yōu)的。這種情形將在周期性的高負(fù)載系統(tǒng)中發(fā)生,我們需要更好的處理這種情況。

這是通過要求所有CPU操作位于一個(gè)每CPU rcu_dynticks 結(jié)構(gòu)中的計(jì)數(shù)器來實(shí)現(xiàn)的。不是那么準(zhǔn)確的說,當(dāng)相應(yīng)的CPU處于dynticks idle模式時(shí),計(jì)數(shù)器的值為偶數(shù),否則是奇數(shù)。這樣,RCU僅僅需要等待rcu_dynticks 計(jì)數(shù)值為奇數(shù)的CPU經(jīng)過靜止?fàn)顟B(tài),而不必喚醒正在睡眠的CPU。如上圖,每一個(gè)每CPU rcu_dynticks結(jié)構(gòu)被“rcu”和“rcu_bh”實(shí)現(xiàn)所共享。

2.6.狀態(tài)機(jī)

從十分高層的視角來看,Linux內(nèi)核RCU 實(shí)現(xiàn)可以被認(rèn)為是一個(gè)高級(jí)狀態(tài)機(jī),如上圖。在一個(gè)很繁忙的系統(tǒng)上,通常的路徑是最上面的兩個(gè)循環(huán)。在每一個(gè)優(yōu)雅周期(GP)開始時(shí)進(jìn)行初始化,等待靜止?fàn)顟B(tài) (QS)。在一個(gè)特定的優(yōu)雅周期中,當(dāng)每一個(gè)CPU都經(jīng)歷過靜止?fàn)顟B(tài)時(shí),它其實(shí)什么都不用做。在這樣一個(gè)系統(tǒng)中,經(jīng)歷如下事件表明產(chǎn)生一個(gè)靜止?fàn)顟B(tài):

1、每一次進(jìn)程切換

2、在CPU進(jìn)入idle狀態(tài)

3、或者執(zhí)行用戶態(tài)代碼時(shí)

CPU熱插撥事件將使?fàn)顟B(tài)機(jī)進(jìn)入“CPU Offline”流程。而“holdout”CPU(那些由于軟件或者硬件原因?qū)е逻t遲不能經(jīng)過一次靜止?fàn)顟B(tài)的CPU)的出現(xiàn),使得不能快速經(jīng)歷一次靜止?fàn)顟B(tài),這將使?fàn)顟B(tài)機(jī)進(jìn)入“send reschedIPIs to Holdout CPUs”(發(fā)送重新調(diào)度IPI給Holdout CPUS)流程。為了避免不必要的喚醒處于dyntick-idle 狀態(tài)的CPU,RCU 實(shí)現(xiàn)將標(biāo)記這些CPU處于擴(kuò)展的靜止?fàn)顟B(tài),通過“Y”分支離開“CPUs in dyntick-idle Mode?”(但是請(qǐng)注意,這些處于dyntick-idle模式的CPU將不會(huì)被發(fā)送重新調(diào)度IPI)。最后,如果CONFIG_RCU_CPU_STALL_DETECTOR打開了,過遲的到達(dá)靜止?fàn)顟B(tài)將使?fàn)顟B(tài)機(jī)進(jìn)入“Complain About Holdout CPUs”流程。

上面的狀態(tài)圖中,事件會(huì)與不同的數(shù)據(jù)結(jié)構(gòu)交互。但是,狀態(tài)圖不會(huì)被任何RCU實(shí)現(xiàn)直接翻譯為C代碼。相反的,這些實(shí)現(xiàn)在內(nèi)核中被編碼為事件驅(qū)動(dòng)的系統(tǒng)。我們通過一些用例來表示這些事件。

2.7.用例

這些事件驅(qū)動(dòng)的用例包括:

1.開始一個(gè)新的優(yōu)雅周期

2.經(jīng)歷一個(gè)靜止?fàn)顟B(tài)

3.向RCU通告一個(gè)靜止?fàn)顟B(tài)

4.進(jìn)入、退出Dynticks Idle 模式

5.從Dynticks Idle 模式進(jìn)入中斷

6.從 Dynticks Idle 模式進(jìn)入NMI

7.標(biāo)記一個(gè)CPU處于Dynticks Idle 模式

8.CPU離線

9.CPU上線

10.檢測(cè)一個(gè)太長(zhǎng)的優(yōu)雅周期

2.7.1.開始一個(gè)新的優(yōu)雅周期

rcu_start_gp()函數(shù)開始一個(gè)新的優(yōu)雅周期。當(dāng)一個(gè)CPU存在回調(diào),而該回調(diào)需要等待優(yōu)雅周期時(shí),就需要調(diào)用此函數(shù)。

rcu_start_gp()函數(shù)更新rcu_state和rcu_data結(jié)構(gòu)中的狀態(tài),以標(biāo)識(shí)開始一個(gè)新的優(yōu)雅周期,獲取->onoff 鎖 (并關(guān)中斷) 以防止任何并發(fā)的CPU熱插撥操作,在所有的rcu_node結(jié)構(gòu)中設(shè)置位,以標(biāo)識(shí)所有CPU (包括當(dāng)前CPU) 必須經(jīng)歷一次靜止?fàn)顟B(tài),最后釋放->onoff 鎖。

設(shè)置位操作分兩個(gè)階段進(jìn)行。首先,在沒有持有任何鎖的情況下,非葉子節(jié)點(diǎn)rcu_node 的位被設(shè)置,然后,在持有->lock的情況下,每一個(gè)葉子節(jié)點(diǎn)的rcu_node 結(jié)構(gòu)的位被設(shè)置。

2.7.2.經(jīng)歷一次靜止?fàn)顟B(tài)

rcu和rcu_bh有各自的靜止?fàn)顟B(tài)集合。

RCU的靜止?fàn)顟B(tài)是進(jìn)程切換、IDLE (不管是dynticks 還是IDLE循環(huán))、以及執(zhí)行用戶態(tài)程序。

RCU-bh的靜止?fàn)顟B(tài)是在開中斷狀態(tài)下,退出軟中斷。

需要注意的是,rcu的靜止?fàn)顟B(tài)也是rcu_bh的靜止?fàn)顟B(tài)。rcu的靜止?fàn)顟B(tài)通過調(diào)用rcu_qsctr_inc()來記錄。而rcu_bh的靜止?fàn)顟B(tài)通過調(diào)用rcu_bh_qsctr_inc()來記錄。這兩個(gè)函數(shù)將它們的狀態(tài)記錄到當(dāng)前CPU的rcu_data 結(jié)構(gòu)中。請(qǐng)注意:在2.6.32版本中,rcu_qsctr_inc和rcu_bh_qsctr_inc函數(shù)已經(jīng)被更名。如何通過git查找它們被更名為什么名稱,這個(gè)任務(wù)就留給作者當(dāng)做練習(xí)了。

這些函數(shù)在調(diào)度器、__do_softirq()和rcu_check_callbacks()中被調(diào)用。后面這個(gè)函數(shù)在調(diào)度時(shí)鐘中斷中調(diào)用,并分析狀態(tài)以確定中斷是否發(fā)生在一個(gè)靜止?fàn)顟B(tài)中,以確定是調(diào)用rcu_qsctr_inc()或者 rcu_bh_qsctr_inc()。它也觸發(fā)RCU_SOFTIRQ軟中斷,并導(dǎo)致當(dāng)前CPU在隨后的軟中斷上下文中調(diào)用rcu_process_callbacks(),rcu_process_callbacks函數(shù)處理RCU在每個(gè)CPU上的回調(diào)函數(shù)以釋放資源。

2.7.3.向RCU宣告一次靜止?fàn)顟B(tài)

前述的rcu_process_callbacks() 函數(shù)要完成幾個(gè)事情:

1.確定何時(shí)結(jié)束一個(gè)太長(zhǎng)的優(yōu)雅周期(通過force_quiescent_state())。

2.當(dāng)CPU檢測(cè)到優(yōu)雅周期結(jié)束時(shí),采用適當(dāng)?shù)膭?dòng)作。(通過 rcu_process_gp_end())?!斑m當(dāng)?shù)膭?dòng)作”包括加快本CPU的回調(diào),以及記錄新的優(yōu)雅周期。同一個(gè)函數(shù)也更新狀態(tài)以響應(yīng)其他CPU。

3.向RCU核心機(jī)制報(bào)告當(dāng)前CPU的靜止?fàn)顟B(tài)。(通過 rcu_check_quiescent_state(),它會(huì)調(diào)用 cpu_quiet())。當(dāng)然,這個(gè)過程也會(huì)標(biāo)記當(dāng)前的優(yōu)雅周期結(jié)束。

4.如果沒有處理優(yōu)雅周期,并且這個(gè)CPU有RCU回調(diào)等待優(yōu)雅周期,則開始一個(gè)新的優(yōu)雅周期(通過 cpu_needs_another_gp()和rcu_start_gp())。

5.當(dāng)優(yōu)雅周期結(jié)束時(shí),調(diào)用這個(gè)CPU的回調(diào) (通過 rcu_do_batch())。

這些接口都經(jīng)過精心實(shí)現(xiàn),以避免BUG,如:錯(cuò)誤的從上一個(gè)優(yōu)雅周期向當(dāng)前優(yōu)雅周期報(bào)告靜止?fàn)顟B(tài)這樣的BUG。

2.7.4.進(jìn)入和退出 Dynticks Idle模式

調(diào)度器調(diào)用rcu_enter_nohz()進(jìn)入dynticks-idle 模式,并調(diào)用 rcu_exit_nohz()離開此模式。rcu_enter_nohz() 函數(shù)遞增每CPU dynticks_nesting變量,也遞增每CPU dynticks計(jì)數(shù)器,然后,后者必然擁有一個(gè)偶數(shù)值。rcu_exit_nohz() 函數(shù)遞減每CPU dynticks_nesting 變量,并且再一次遞增每CPU dynticks計(jì)數(shù)器,后者將擁有一個(gè)奇數(shù)值。

dynticks 計(jì)數(shù)器可以被其他 CPU采樣。如果其值是偶數(shù),那么該CPU處于擴(kuò)展靜止?fàn)顟B(tài)。類似的,如果計(jì)數(shù)器在一個(gè)特定的優(yōu)雅周期內(nèi)發(fā)生了改變,那么CPU必然在優(yōu)雅周期期間的某個(gè)時(shí)間點(diǎn)上處于擴(kuò)展靜止?fàn)顟B(tài)。但是,還需要采樣另外一個(gè)dynticks_nmi每CPU變量,隨后我們將討論這個(gè)變量。

2.7.5.從Dynticks Idle 模式進(jìn)入中斷

從dynticks idle 模式進(jìn)入中斷由rcu_irq_enter() 和 rcu_irq_exit()處理。rcu_irq_enter() 函數(shù)遞增每CPU dynticks_nesting 變量,如果此變量為0,也遞增dynticks每CPU變量 (它將擁有一個(gè)奇數(shù)值)。

rcu_irq_exit()函數(shù)遞減每CPU dynticks_nesting變量。并且,如果新值是0,也遞增dynticks每CPU變量 (它將擁有一個(gè)偶數(shù)值)。

注意:進(jìn)入中斷會(huì)處理退出dynticks idle模式,反之也一樣。進(jìn)入、退出之間不一致可能導(dǎo)致一些混亂,不用警告你也應(yīng)該想得到這一點(diǎn)。

2.7.6.從Dynticks Idle 模式進(jìn)入NMI

從dynticks idle模式進(jìn)入NMI由rcu_nmi_enter()和rcu_nmi_exit()處理。這些函數(shù)同時(shí)遞增dynticks_nmi計(jì)數(shù)器,但僅僅是在前述dynticks 計(jì)數(shù)是偶數(shù)時(shí)才進(jìn)行遞增。換句話說,如果NMI發(fā)生時(shí),處于非dynticks-idle模式或者處于中斷狀態(tài),那么 NMI將不操作dynticks_nmi計(jì)數(shù)器。

這兩個(gè)函數(shù)之間唯一的差異在于錯(cuò)誤檢查,rcu_nmi_enter()必然使dynticks_nmi計(jì)數(shù)器為奇數(shù)值,rcu_nmi_exit()必然使這個(gè)計(jì)數(shù)器為偶數(shù)值。

2.7.7.標(biāo)記CPU處于Dynticks Idle模式

force_quiescent_state()函數(shù)實(shí)現(xiàn)一個(gè)三階段的狀態(tài)機(jī)。 第一個(gè)階段 (RCU_INITIALIZING)等待rcu_start_gp()完成對(duì)優(yōu)雅周期的初始化。這個(gè)狀態(tài)不是從force_quiescent_state()退出,就是從rcu_start_gp()退出。

在第二階段(RCU_SAVE_DYNTICK),dyntick_save_progress_counter()函數(shù)掃描還沒有報(bào)告靜止?fàn)顟B(tài)的CPU,記錄它們的每CPU dynticks 和dynticks_nmi 計(jì)數(shù)器。如果這些計(jì)數(shù)器都是偶數(shù)值,那么相應(yīng)的CPU處于dynticks-idle 狀態(tài),因此標(biāo)記它們?yōu)閿U(kuò)展靜止?fàn)顟B(tài)(通過cpu_quiet_msk()報(bào)告)。

在第三階段(RCU_FORCE_QS),rcu_implicit_dynticks_qs()函數(shù)再一次掃描仍然沒有報(bào)告靜止?fàn)顟B(tài)的CPU (既沒有明確標(biāo)示,也沒有在RCU_SAVE_DYNTICK階段隱含的標(biāo)示),再一次檢查每CPU dynticks 和 dynticks_nmi計(jì)數(shù)器。如果每一個(gè)值都變化,或者目前為偶數(shù),那么相應(yīng)的相應(yīng)的CPU已經(jīng)經(jīng)過一次靜止?fàn)顟B(tài)或者目前處于dynticks idle模式,也就是前述擴(kuò)展靜止?fàn)顟B(tài)。

如果rcu_implicit_dynticks_qs()發(fā)現(xiàn)特定CPU既沒有處于dynticks idle模式,也沒有報(bào)告一個(gè)靜止?fàn)顟B(tài),它調(diào)用rcu_implicit_offline_qs(),這個(gè)函數(shù)檢查CPU是否處于離線狀態(tài),如果是,那么也報(bào)告一個(gè)擴(kuò)展靜止?fàn)顟B(tài)。如果CPU在線,那么rcu_implicit_offline_qs()發(fā)送一個(gè)重新調(diào)度IPI,嘗試提醒該CPU應(yīng)當(dāng)向RCU報(bào)告一個(gè)靜止?fàn)顟B(tài)。

請(qǐng)注意:force_quiescent_state() 既不直接調(diào)用dyntick_save_progress_counter(),也不直接調(diào)用rcu_implicit_dynticks_qs(),而是將它們傳遞給rcu_process_dyntick() 函數(shù)。這個(gè)函數(shù)抽象出掃描CPU、報(bào)告擴(kuò)展靜止?fàn)顟B(tài)的通用代碼。

2.7.8.CPU離線

CPU離線事件導(dǎo)致rcu_cpu_notify()調(diào)用rcu_offline_cpu(),在rcu和rcu_bh上依次調(diào)用__rcu_offline_cpu()。這個(gè)函數(shù)清除離線CPU的位,這樣,后面的優(yōu)雅周期將不再期望這個(gè)CPU宣告靜止?fàn)顟B(tài),隨后調(diào)用cpu_quiet(),以宣告離線擴(kuò)展靜止?fàn)顟B(tài)。這是在持有全局->onofflock鎖的情況下執(zhí)行的,這是為了防止與優(yōu)雅周期初始化相沖突。

2.7.9.CPU上線

CPU上線事件導(dǎo)致rcu_cpu_notify()調(diào)用rcu_online_cpu(),用于初始化CPU的dynticks狀態(tài),然后調(diào)用rcu_init_percpu_data()初始化CPU的rcu_data 數(shù)據(jù)結(jié)構(gòu),也設(shè)置這個(gè) CPU的位(同樣通過全局->onofflock進(jìn)行保護(hù)),這樣后面的優(yōu)雅周期將等待這個(gè)CPU的靜止?fàn)顟B(tài)。最后,rcu_online_cpu()設(shè)置這個(gè)CPU的RCU 軟中斷向量。

2.7.10.檢測(cè)太長(zhǎng)的優(yōu)雅周期

當(dāng)配置了CONFIG_RCU_CPU_STALL_DETECTOR內(nèi)核參數(shù)時(shí),record_gp_stall_check_time() 函數(shù)記錄當(dāng)前時(shí)間,以及3秒以后的時(shí)間戳。如果當(dāng)前優(yōu)雅周期到期后仍然沒有結(jié)束,那么check_cpu_stall函數(shù)將檢測(cè)罪魁禍?zhǔn)住2⑶胰绻?dāng)前CPU是造成延遲的CPU,則調(diào)用print_cpu_stall(),如果不是,則調(diào)用print_other_cpu_stall()。兩個(gè)jiffies的時(shí)間差有助于確保其他CPU在可能的情況下報(bào)告它的狀態(tài),利用這個(gè)時(shí)間差,CPU能夠做一些事情,例如跟蹤它自己的堆棧。

2.8.測(cè)試

RCU是基本的同步代碼,因此RCU的錯(cuò)誤導(dǎo)致的后果是隨機(jī)的、難于調(diào)試的內(nèi)存錯(cuò)誤。因此,高可靠的RCU是非常重要的。這些可靠性來自于小心的設(shè)計(jì),但是最終還是需要依賴于高強(qiáng)度的壓力測(cè)試。

幸運(yùn)的是,雖然有一些關(guān)于覆蓋性方面的爭(zhēng)論,但是仍然可以對(duì)軟件進(jìn)行一些壓力測(cè)試。實(shí)際上,進(jìn)行這些測(cè)試是被強(qiáng)烈建議的,因?yàn)椴粚?duì)你的軟件進(jìn)行折磨性測(cè)試的話,它就會(huì)反過來折磨你,這種折磨來自于:它在不合時(shí)宜的時(shí)候崩潰掉。

因此,我們使用rcutorture模塊來對(duì)RCU進(jìn)行壓力測(cè)試。

但是,根據(jù)通常情況下的RCU用法來對(duì)RCU進(jìn)行測(cè)試,顯得還不是很充分。也有必要針對(duì)不常用的情況進(jìn)行壓力測(cè)試。例如,CPU并發(fā)的上線或者離線,CPU并發(fā)的進(jìn)入及退出dynticks idle模式。Paul使用了一個(gè)腳本CodeSamples,并向模塊rcutorture使用test_no_idle_hz 模塊參數(shù)對(duì)dynticks idle模式進(jìn)行壓力測(cè)試。有時(shí)作者也比較疑神疑鬼,因此盡量在測(cè)試時(shí)運(yùn)行一個(gè)kernbench負(fù)載測(cè)試程序。在128路的機(jī)器上運(yùn)行10個(gè)小時(shí)的壓力測(cè)試,看起來是足夠測(cè)試出幾乎所有BUG了。

實(shí)際上這還不算完。Alexey Dobriyan和Nick Piggin早在2008年就證明過,以所有相關(guān)內(nèi)核參數(shù)組合對(duì)RCU進(jìn)行壓力測(cè)試是必要的。相關(guān)的內(nèi)核參數(shù)可以使用另外一個(gè)腳本CodeSamples進(jìn)行標(biāo)識(shí)。

1.CONFIG_CLASSIC_RCU:經(jīng)典 RCU。

2.CONFIG_PREEMPT_RCU:可搶占 (實(shí)時(shí)) RCU。

3.CONFIG_TREE_RCU:用于大型SMP系統(tǒng)的經(jīng)典 RCU。

4.CONFIG_RCU_FANOUT:每一個(gè)rcu_node 的子結(jié)點(diǎn)數(shù)量。

5.CONFIG_RCU_FANOUT_EXACT:平衡rcu_node 樹。

6.CONFIG_HOTPLUG_CPU:允許 CPU上線、離線。

7.CONFIG_NO_HZ:打開dyntick-idle 模式。

8.CONFIG_SMP:打開 multi-CPU選項(xiàng)。

9.CONFIG_RCU_CPU_STALL_DETECTOR:當(dāng)CPU進(jìn)入擴(kuò)展靜止?fàn)顟B(tài)時(shí)進(jìn)行RCU檢測(cè)。

10.CONFIG_RCU_TRACE:在debugfs中生成 RCU跟蹤文件。

我們忽略CONFIG_DEBUG_LOCK_ALLOC 配置變量,因?yàn)槲覀兗僭O(shè)分級(jí)RCU不能打斷 lockdep。仍然有10個(gè)配置變量,如果它們是獨(dú)立的布爾值,則導(dǎo)致1024種組合。幸運(yùn)的是,首先,其中前三個(gè)是互斥的,這樣可以將組合數(shù)量減少到384個(gè),但是CONFIG_RCU_FANOUT可以取值2-64,將組合數(shù)量增加到12,096。這么大量的組合是不可能都實(shí)施的。

關(guān)鍵的一點(diǎn)是:如果CONFIG_CLASSIC_RCU或者CONFIG_PREEMPT_RCU有效時(shí),預(yù)期僅僅CONFIG_NO_HZ 和 CONFIG_PREEMPT 可能會(huì)改變其行為。這幾乎減少了三分之二的組合。

而且,并不是這些所有可能的CONFIG_RCU_FANOUT值都會(huì)產(chǎn)生顯著有效的結(jié)果,實(shí)際上僅僅一部分情況需要分別測(cè)試:

1.單結(jié)點(diǎn)“tree”。

2.兩級(jí)平衡樹。

3.三級(jí)平衡樹。

4.自動(dòng)平衡樹,當(dāng) CONFIG_RCU_FANOUT 指定一個(gè)不平衡樹,但是沒有配置CONFIG_RCU_FANOUT_EXACT 時(shí),進(jìn)行自動(dòng)平衡。

5.非平衡樹。

更進(jìn)一步說,CONFIG_HOTPLUG_CPU僅僅在指定CONFIG_SMP 時(shí)才有用,CONFIG_RCU_CPU_STALL_DETECTOR是獨(dú)立的,因此僅僅需要測(cè)試一次(然而有些人比我還多疑,他們可能決定在有CONFIG_SMP和沒有CONFIG_SMP 時(shí),都測(cè)試它)。類似的,CONFIG_RCU_TRACE也僅僅需要測(cè)試一次。但是象我一樣多疑的人,會(huì)選擇在有CONFIG_NO_HZ 和沒有CONFIG_NO_HZ 時(shí),都測(cè)試一下它。

這允許我們?cè)?5種測(cè)試情形下,得到一個(gè)覆蓋率較好的RCU測(cè)試。所有這些測(cè)試情形都指定如下配置參數(shù)以運(yùn)行rcutorture,這樣CONFIG_HOTPLUG_CPU=n會(huì)產(chǎn)生實(shí)際的效果:

CONFIG_RCU_TORTURE_TEST=m

CONFIG_MODULE_UNLOAD=y

CONFIG_SUSPEND=n

CONFIG_HIBERNATION=n

15個(gè)測(cè)試用例如下:

1.強(qiáng)制單節(jié)點(diǎn)“樹”,用于小型系統(tǒng):

CONFIG_NR_CPUS=8

CONFIG_RCU_FANOUT=8

CONFIG_RCU_FANOUT_EXACT=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

2.強(qiáng)制兩級(jí)節(jié)點(diǎn)樹用于大型系統(tǒng):

CONFIG_NR_CPUS=8

CONFIG_RCU_FANOUT=4

CONFIG_RCU_FANOUT_EXACT=n

CONFIG_RCU_TRACE=n

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

3.強(qiáng)制三級(jí)節(jié)點(diǎn)樹,用于非常大型的系統(tǒng):

CONFIG_NR_CPUS=8

CONFIG_RCU_FANOUT=2

CONFIG_RCU_FANOUT_EXACT=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

4.測(cè)試自動(dòng)平衡:

CONFIG_NR_CPUS=8

CONFIG_RCU_FANOUT=6

CONFIG_RCU_FANOUT_EXACT=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

5.測(cè)試不平衡樹:

CONFIG_NR_CPUS=8

CONFIG_RCU_FANOUT=6

CONFIG_RCU_FANOUT_EXACT=y

CONFIG_RCU_CPU_STALL_DETECTOR=y

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

6.禁止CPU延遲檢測(cè):

CONFIG_SMP=y

CONFIG_NO_HZ=y

CONFIG_RCU_CPU_STALL_DETECTOR=n

CONFIG_HOTPLUG_CPU=y

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

7.禁止 CPU延遲檢測(cè)及dyntick idle 模式:

CONFIG_SMP=y

CONFIG_NO_HZ=n

CONFIG_RCU_CPU_STALL_DETECTOR=n

CONFIG_HOTPLUG_CPU=y

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

8.禁止 CPU延遲檢測(cè)及CPU熱插撥:

CONFIG_SMP=y

CONFIG_NO_HZ=y

CONFIG_RCU_CPU_STALL_DETECTOR=n

CONFIG_HOTPLUG_CPU=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

9.禁止 CPU延遲檢測(cè),dyntick idle 模式,及CPU熱插撥:

CONFIG_SMP=y

CONFIG_NO_HZ=n

CONFIG_RCU_CPU_STALL_DETECTOR=n

CONFIG_HOTPLUG_CPU=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

10.禁止SMP、CPU延遲檢測(cè)、dyntick idle 模式、及CPU熱插撥:

CONFIG_SMP=n

CONFIG_NO_HZ=n

CONFIG_RCU_CPU_STALL_DETECTOR=n

CONFIG_HOTPLUG_CPU=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

這個(gè)組合有一些編譯警告。

11.禁止SMP、禁止CPU熱插撥:

CONFIG_SMP=n

CONFIG_NO_HZ=y

CONFIG_RCU_CPU_STALL_DETECTOR=y

CONFIG_HOTPLUG_CPU=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=y

12.有dynticks idle 但是沒有搶占的情況下,測(cè)試經(jīng)典RCU:

CONFIG_NO_HZ=y

CONFIG_PREEMPT=n

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=y

CONFIG_TREE_RCU=n

13.有搶占但是沒有dynticks idle時(shí),測(cè)試經(jīng)典RCU:

CONFIG_NO_HZ=n

CONFIG_PREEMPT=y

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=n

CONFIG_CLASSIC_RCU=y

CONFIG_TREE_RCU=n

14.在dynticks idle情況下,測(cè)試可搶占RCU:

CONFIG_NO_HZ=y

CONFIG_PREEMPT=y

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=y

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=n

15.在沒有 dynticks idle時(shí),測(cè)試可搶占RCU:

CONFIG_NO_HZ=n

CONFIG_PREEMPT=y

CONFIG_RCU_TRACE=y

CONFIG_PREEMPT_RCU=y

CONFIG_CLASSIC_RCU=n

CONFIG_TREE_RCU=n

對(duì)于每一次大的影響RCU核心代碼的變化,都應(yīng)當(dāng)以上面的組合運(yùn)行rcutorture,并且在CONFIG_HOTPLUG_CPU時(shí),并發(fā)的進(jìn)行CPU熱插撥。對(duì)小的變化,在每一種情況下運(yùn)行kernbench就行了。當(dāng)然,如果變化僅僅限于配置參數(shù)的部分子集,就可以減少測(cè)試用例的數(shù)量。

作者強(qiáng)烈推薦壓力測(cè)試軟件:Geneva Convention!

2.9.結(jié)論

這個(gè)分級(jí)RCU實(shí)現(xiàn)減少了鎖競(jìng)爭(zhēng),避免了不必要的喚醒dyntick-idle睡眠狀態(tài)的CPU,因此有助于調(diào)試Linux CPU熱插撥代碼。這個(gè)實(shí)現(xiàn)被設(shè)計(jì)用于處理數(shù)千個(gè)CPU的大型系統(tǒng),并且在64位系統(tǒng)上,CPU數(shù)量限制是250,000,在今后一段時(shí)間內(nèi),這個(gè)限制是沒有問題的。

這個(gè)RCU實(shí)現(xiàn)當(dāng)然也有一些局限:

1.force_quiescent_state()可能在關(guān)中斷下掃描整個(gè)CPU集。這在實(shí)時(shí)RCU實(shí)現(xiàn)中,是一個(gè)重大缺陷。因此,如果需要在可搶占RCU中加入分級(jí),則需要其他方法。在4096個(gè)CPU的系統(tǒng)中,它可能會(huì)產(chǎn)生一些問題,但是需要在實(shí)際的系統(tǒng)中進(jìn)行測(cè)試以證明真的有問題。

在繁忙的系統(tǒng)中,不能指望force_quiescent_state()掃描會(huì)發(fā)生,CPU將在開始一個(gè)靜止?fàn)顟B(tài)后,在三個(gè)jiffies內(nèi)經(jīng)歷一次靜止?fàn)顟B(tài)。在半繁忙的系統(tǒng)中,僅僅處于dynticks-idle模式的CPU需要掃描。其他情況下,例如,在一個(gè)dynticks-idle CPU掃描過程中,處理一個(gè)中斷時(shí),后繼的掃描是需要的。但是,這樣的掃描是分別在相應(yīng)的CPU上執(zhí)行的,因此相應(yīng)的調(diào)度延遲僅僅影響該掃描過程所在的CPU負(fù)載。

如果掃描被證明確實(shí)有問題,一個(gè)好的方法是進(jìn)行遞增掃描。這將稍微增加一點(diǎn)代碼復(fù)雜性,也增加一點(diǎn)結(jié)束優(yōu)雅周期的時(shí)間,但是這也確實(shí)算是一個(gè)好的方案。

2.rcu_node分級(jí)在編譯時(shí)創(chuàng)建,因此其長(zhǎng)度是最大的CPU數(shù)量NR_CPUS。 但是,即使在4,096 CPU的系統(tǒng)中,在64位系統(tǒng)上,rcu_node 分級(jí)也僅僅消耗65個(gè)緩存行。(即使在32位系統(tǒng)上包含4,096 CPUs也是這樣!)。當(dāng)然,在一個(gè)16 CPU的系統(tǒng)中,配置NR_CPUS=4096將使用一個(gè)二級(jí)樹,實(shí)際上在這種情況下,單節(jié)點(diǎn)樹也會(huì)運(yùn)行得很好。雖然這個(gè)配置會(huì)增加鎖的負(fù)載,但是實(shí)際上不會(huì)影響經(jīng)常執(zhí)行的讀端代碼,因此事實(shí)上不會(huì)有太大的問題。

3.這個(gè)補(bǔ)丁會(huì)稍微增加內(nèi)核代碼及數(shù)據(jù)尺寸:在NR_CPUS=4的系統(tǒng)中,從經(jīng)典RCU的1,757字節(jié)內(nèi)核代碼、456字節(jié)數(shù)據(jù),共2213字節(jié)的內(nèi)核尺寸,而分級(jí)RCU則增加到4,006字節(jié)的內(nèi)核代碼、624字節(jié)的內(nèi)核數(shù)據(jù),共計(jì)4,630字節(jié)尺寸。即使對(duì)大多數(shù)嵌入式系統(tǒng)來說,這也不是一個(gè)問題。這些系統(tǒng)通常有上百兆主內(nèi)存。但是對(duì)特別小的系統(tǒng)來說,這可能就是一個(gè)問題了,需要提供兩種類型的RCU實(shí)現(xiàn)以滿足這樣的嵌入式系統(tǒng)。不過有一個(gè)有趣的問題,在這樣的系統(tǒng)中,也許僅僅包含一個(gè)CPU,這樣的系統(tǒng)完全可以用一個(gè)特別簡(jiǎn)單的RCU實(shí)現(xiàn)。

即使有這些問題,相對(duì)于經(jīng)典RCU來說,在數(shù)百個(gè)CPU的系統(tǒng)中,這個(gè)分級(jí)RCU實(shí)現(xiàn)仍然是一個(gè)巨大的進(jìn)步。最后需要說明一下,經(jīng)典RCU設(shè)計(jì)用于16-32個(gè)CPU的系統(tǒng)。

在某些地方,在可搶占RCU實(shí)現(xiàn)中使用分級(jí)是有必要的。

后續(xù)章節(jié)將繼續(xù)分析分級(jí)RCU的代碼,以及Linux中其他一些RCU的實(shí)現(xiàn)。也許還會(huì)討論實(shí)現(xiàn)RCU這類復(fù)雜并行軟件的開發(fā)方法及其形式化驗(yàn)證。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10805

    瀏覽量

    210850
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11212

    瀏覽量

    208721
  • rcu
    rcu
    +關(guān)注

    關(guān)注

    0

    文章

    21

    瀏覽量

    5435

原文標(biāo)題:謝寶友:深入理解RCU之六:分級(jí)RCU基礎(chǔ)

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    謝寶友教你學(xué)Linux深入理解Linux RCU之從硬件說起

    RCULinux內(nèi)核中很難的一部分,本系列文章一點(diǎn)一滴地來把RCU說清楚。第一次連載,是描述硬件。
    的頭像 發(fā)表于 09-04 10:29 ?5953次閱讀
    謝寶友教你學(xué)<b class='flag-5'>Linux</b>:<b class='flag-5'>深入理解</b><b class='flag-5'>Linux</b> <b class='flag-5'>RCU</b>之從硬件說起

    從硬件引申出內(nèi)存屏障,帶你深入了解Linux內(nèi)核RCU

    本文從硬件的角度引申出內(nèi)存屏障,這不是內(nèi)存屏障的詳盡手冊(cè),但是相關(guān)知識(shí)對(duì)于理解RCU有所幫助。
    的頭像 發(fā)表于 09-19 11:39 ?6107次閱讀
    從硬件引申出內(nèi)存屏障,帶你<b class='flag-5'>深入</b>了解<b class='flag-5'>Linux</b>內(nèi)核<b class='flag-5'>RCU</b>

    基于Linux內(nèi)核源碼的RCU實(shí)現(xiàn)方案

    RCU(Read-Copy Update)是數(shù)據(jù)同步的一種方式,在當(dāng)前的Linux內(nèi)核中發(fā)揮著重要的作用。RCU主要針對(duì)的數(shù)據(jù)對(duì)象是鏈表,目的是提高遍歷讀取數(shù)據(jù)的效率,為了達(dá)到目的使用RCU
    的頭像 發(fā)表于 09-25 15:10 ?2423次閱讀

    Linux內(nèi)核RCU鎖的原理與使用

    好久沒有更文,上次更文時(shí)西安天氣還很熱,現(xiàn)在“寒氣”它還真來了。在前一階段經(jīng)歷了一些公司的面試,經(jīng)常會(huì)問到RCU鎖的原理,其實(shí)在跟對(duì)方口述表達(dá)時(shí)才真正能體現(xiàn)出來自己到底懂不懂,關(guān)于RCU鎖的原理與使用,我打算分若干個(gè)次文章整理出來,本次就先從一個(gè)大概的原理上進(jìn)行講解。
    發(fā)表于 10-13 16:17 ?4569次閱讀
    <b class='flag-5'>Linux</b>內(nèi)核<b class='flag-5'>RCU</b>鎖的原理與使用

    深入理解RCU:玩具式實(shí)現(xiàn)

    也許最簡(jiǎn)單的RCU實(shí)現(xiàn)就是用鎖了,如下圖所示。在該實(shí)現(xiàn)中,rcu_read_lock()獲取一把全局自旋鎖,rcu_read_unlock(
    的頭像 發(fā)表于 12-27 09:06 ?698次閱讀

    分級(jí)RCU的基礎(chǔ)知識(shí)

    雖然Linux更早版本中的經(jīng)典RCU,其讀端原語擁有出色的性能和擴(kuò)展性,但是寫端原語則需要判斷預(yù)先存在的讀端臨界區(qū)在什么時(shí)候完成,它僅僅被設(shè)計(jì)用于數(shù)十個(gè)CPU的系統(tǒng)。經(jīng)典
    的頭像 發(fā)表于 12-27 09:54 ?893次閱讀
    分級(jí)<b class='flag-5'>RCU</b>的基礎(chǔ)知識(shí)

    Linux內(nèi)核中RCU的用法

    Linux內(nèi)核中,RCU最常見的用途是替換讀寫鎖。在20世紀(jì)90年代初期,Paul在實(shí)現(xiàn)通用RCU之前,實(shí)現(xiàn)了一種輕量級(jí)的讀寫鎖。后來,為
    的頭像 發(fā)表于 12-27 09:56 ?1617次閱讀
    <b class='flag-5'>Linux</b>內(nèi)核中<b class='flag-5'>RCU</b>的用法

    深入理解Linux內(nèi)核 中文版+英文原版

    深入理解Linux內(nèi)核 中文版+英文原版 經(jīng)典之作
    發(fā)表于 05-17 08:18

    分級(jí)RCU基礎(chǔ)知識(shí)

    謝寶友:深入理解RCU之六:分級(jí)RCU基礎(chǔ)
    發(fā)表于 05-25 06:18

    linux經(jīng)典rcu如何實(shí)現(xiàn)?

    RCU主要用于對(duì)性能要求苛刻的并行實(shí)時(shí)計(jì)算。例如:天氣預(yù)報(bào)、模擬核爆炸計(jì)算、內(nèi)核同步等等。
    的頭像 發(fā)表于 11-07 11:09 ?3710次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>經(jīng)典</b>的<b class='flag-5'>rcu</b>如何<b class='flag-5'>實(shí)現(xiàn)</b>?

    linux內(nèi)核rcu機(jī)制詳解

    Linux內(nèi)核源碼當(dāng)中,關(guān)于RCU的文檔比較齊全,你可以在 /Documentation/RCU/ 目錄下找到這些文件。Paul E. McKenney 是內(nèi)核中RCU源碼的主要
    發(fā)表于 11-13 16:47 ?8744次閱讀
    <b class='flag-5'>linux</b>內(nèi)核<b class='flag-5'>rcu</b>機(jī)制詳解

    深入理解Linux RCU:RCU是讀寫鎖的替代者

    請(qǐng)注意,在單個(gè)CPU上讀寫鎖比RCU慢一個(gè)數(shù)量級(jí),在16個(gè)CPU上讀寫鎖比RCU幾乎要慢兩個(gè)數(shù)量級(jí)。隨著CPU數(shù)量的增加,RCU的擴(kuò)展性優(yōu)勢(shì)越來越突出??梢赃@么說,RCU幾乎就是水平擴(kuò)
    的頭像 發(fā)表于 05-10 09:13 ?1.1w次閱讀
    <b class='flag-5'>深入理解</b><b class='flag-5'>Linux</b> <b class='flag-5'>RCU</b>:<b class='flag-5'>RCU</b>是讀寫鎖的替代者

    深入了解RCU是怎樣實(shí)現(xiàn)的?

    RCU(Read-Copy Update),顧名思義就是讀-拷貝修改,它是基于其原理命名的。對(duì)于被RCU保護(hù)的共享數(shù)據(jù)結(jié)構(gòu),讀者不需要獲得任何鎖就可以訪問它,但寫者在訪問它時(shí)首先拷貝一個(gè)副本,然后
    發(fā)表于 05-14 17:37 ?1.4w次閱讀
     <b class='flag-5'>深入</b>了解<b class='flag-5'>RCU</b>是怎樣<b class='flag-5'>實(shí)現(xiàn)</b>的?

    了解了解Linux內(nèi)核中的RCU機(jī)制

    RCU的設(shè)計(jì)思想比較明確,通過新老指針替換的方式來實(shí)現(xiàn)免鎖方式的共享保護(hù)。但是具體到代碼的層面,理解起來多少還是會(huì)有些困難。在《深入Linux
    發(fā)表于 05-14 14:28 ?1330次閱讀

    并行程序設(shè)計(jì)中最重要的鎖-RCU

    ,。 各個(gè)語言C, C++,Java, go等都有RCU實(shí)現(xiàn),同時(shí)內(nèi)核精巧的實(shí)現(xiàn)也是學(xué)習(xí)代碼設(shè)計(jì)好素材,深入理解RCU分為兩個(gè)部分,第一部
    的頭像 發(fā)表于 08-27 14:25 ?3095次閱讀