英語

RCU 壓力測試操作

CONFIG_RCU_TORTURE_TEST

CONFIG_RCU_TORTURE_TEST 配置選項可用於所有 RCU 實現。它建立了一個 rcutorture 核心模組,可以載入該模組來執行壓力測試。測試會定期透過 printk() 輸出狀態訊息,可以使用 dmesg 命令(可能使用 grep 搜尋 “torture”)檢查這些訊息。測試在載入模組時啟動,並在解除安裝模組時停止。

模組引數以 “rcutorture.” 為字首,位於 核心的命令列引數 中。

輸出

統計資訊輸出如下

rcu-torture:--- Start of test: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4
rcu-torture: rtc:           (null) ver: 155441 tfle: 0 rta: 155441 rtaf: 8884 rtf: 155440 rtmbe: 0 rtbe: 0 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 3055767
rcu-torture: Reader Pipe:  727860534 34213 0 0 0 0 0 0 0 0 0
rcu-torture: Reader Batch:  727877838 17003 0 0 0 0 0 0 0 0 0
rcu-torture: Free-Block Circulation:  155440 155440 155440 155440 155440 155440 155440 155440 155440 155440 0
rcu-torture:--- End of test: SUCCESS: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4

命令 “dmesg | grep torture:” 將在大多數系統上提取此資訊。在更深奧的配置中,可能需要使用其他命令來訪問 RCU 壓力測試使用的 printk() 的輸出。 printk() 使用 KERN_ALERT,因此它們應該很明顯。 ;-)

第一行和最後一行顯示 rcutorture 模組引數,最後一行根據 rcutorture 對 RCU 是否正常執行的自動判斷顯示 “SUCCESS” 或 “FAILURE”。

條目如下

  • “rtc”: 當前讀者可見的結構的十六進位制地址。

  • “ver”: 自啟動以來 RCU 寫入器任務更改讀者可見結構的次數。

  • “tfle”: 如果非零,則表示包含要放入 “rtc” 區域的結構的 “torture freelist” 為空。這種情況很重要,因為它會欺騙您,讓您認為 RCU 工作正常,而實際上並非如此。 :-/

  • “rta”: 從 torture freelist 分配的結構數量。

  • “rtaf”: 由於列表為空而導致從 torture freelist 分配失敗的次數。這通常不是零,但如果它佔 “rta” 指示值的很大一部分,則情況不妙。

  • “rtf”: 釋放到 torture freelist 中的數量。

  • “rtmbe”: 非零值表示 rcutorture 認為 rcu_assign_pointer()rcu_dereference() 工作不正常。此值應為零。

  • “rtbe”: 非零值表示 rcu_barrier() 函式系列之一工作不正常。

  • “rtbke”: rcutorture 無法建立用於強制 RCU 優先順序反轉的即時 kthread。此值應為零。

  • “rtbre”: 儘管 rcutorture 成功建立了用於強制 RCU 優先順序反轉的 kthread,但它無法將它們設定為 1 的即時優先順序級別。此值應為零。

  • “rtbf”: RCU 優先順序提升未能解決 RCU 優先順序反轉的次數。

  • “rtb”: rcutorture 嘗試強制 RCU 優先順序反轉條件的次數。如果您正在透過 “test_boost” 模組引數測試 RCU 優先順序提升,則此值應為非零。

  • “nt”: rcutorture 從定時器處理程式中執行 RCU 讀取端程式碼的次數。僅當您指定了 “irqreader” 模組引數時,此值才應為非零。

  • “Reader Pipe”: 讀者看到的結構“年齡”的直方圖。如果前兩個條目之後的任何條目為非零,則 RCU 已損壞。 rcutorture 會列印錯誤標誌字串 “!!!” 以確保您注意到。新分配結構的年齡為零,從讀者可見性中刪除時變為一,然後在每個寬限期內遞增一次 — 並在經過 (RCU_TORTURE_PIPE_LEN-2) 個寬限期後釋放。

    上面顯示的輸出來自正常工作的 RCU。如果您想看看損壞時的樣子,請自行將其損壞。 ;-)

  • “Reader Batch”: 讀者看到的結構“年齡”的另一個直方圖,但以計數器翻轉(或批次)而不是寬限期來衡量。非零條目的合法數量再次為兩個。這種單獨檢視的原因是,有時更容易在 “Reader Batch” 列表中而不是在 “Reader Pipe” 列表中顯示第三個條目。

  • “Free-Block Circulation”: 顯示已達到管道中給定點的 torture 結構的數量。第一個元素應與分配的結構數量緊密對應,第二個元素應與已從讀者檢視中刪除的數量緊密對應,除最後一個元素之外的所有元素都應與透過寬限期的相應次數緊密對應。最後一個條目應為零,因為它僅在 torture 結構的計數器以某種方式遞增到超出應有範圍時才會遞增。

RCU 的不同實現可以提供特定於實現的其他資訊。例如,Tree SRCU 提供以下附加行

srcud-torture: Tree SRCU per-CPU(idx=0): 0(35,-21) 1(-4,24) 2(1,1) 3(-26,20) 4(28,-47) 5(-9,4) 6(-10,14) 7(-14,11) T(1,6)

此行顯示每個 CPU 的計數器狀態,在本例中為 Tree SRCU,它使用動態分配的 srcu_struct(因此為 “srcud-” 而不是 “srcu-“)。括號中的數字是相應 CPU 的 “old” 和 “current” 計數器的值。“idx” 值將 “old” 和 “current” 值對映到底層陣列,這對於除錯很有用。最後一個 “T” 條目包含計數器的總計。

在特定核心版本上使用

有時需要在特定核心版本上對 RCU 進行壓力測試,例如,在準備將該核心版本投入生產時。在這種情況下,應使用 CONFIG_RCU_TORTURE_TEST=m 構建核心,以便可以使用 modprobe 啟動測試,並使用 rmmod 終止測試。

例如,可以使用以下指令碼對 RCU 進行壓力測試

#!/bin/sh

modprobe rcutorture
sleep 3600
rmmod rcutorture
dmesg | grep torture:

可以手動檢查輸出中是否包含錯誤標誌 “!!!”。當然,您可以建立一個更復雜的指令碼來自動檢查此類錯誤。“rmmod” 命令強制 printk() “SUCCESS”、“FAILURE” 或 “RCU_HOTPLUG” 指示。前兩個是不言自明的,而最後一個表示雖然沒有 RCU 故障,但檢測到 CPU 熱插拔問題。

在主線核心上使用

當使用 rcutorture 測試對 RCU 本身的更改時,通常需要構建多個核心,以便在相關 Kconfig 選項和相關核心啟動引數的廣泛組合中測試該更改。在這種情況下,使用 modprobe 和 rmmod 可能會非常耗時且容易出錯。

因此,tools/testing/selftests/rcutorture/bin/kvm.sh 指令碼可用於 x86、arm64 和 powerpc 的主線測試。預設情況下,它將執行 tools/testing/selftests/rcutorture/configs/rcu/CFLIST 指定的一系列測試,每個測試在使用自動生成的 initrd 提供的最小使用者空間的 Guest OS 中執行 30 分鐘。測試完成後,將分析生成的構建產品和控制檯輸出是否存在錯誤,並彙總執行結果。

在較大的系統上,可以透過將 --cpus 引數傳遞給 kvm.sh 來加速 rcutorture 測試。例如,在 64 CPU 系統上,“--cpus 43” 將使用多達 43 個 CPU 併發執行測試,在 v5.4 中,這將以兩個批次完成所有場景,從而將完成時間從大約 8 小時減少到大約 1 小時(不包括構建 16 個核心的時間)。 “--dryrun sched” 引數不會執行測試,而是告訴您如何將測試安排到批次中。在計算在 --cpus 引數中指定多少個 CPU 時,這可能很有用。

並非所有更改都需要執行所有場景。例如,對 Tree SRCU 的更改可能只執行 SRCU-N 和 SRCU-P 場景,使用 kvm.sh 的 --configs 引數,如下所示:“--configs ‘SRCU-N SRCU-P’”。大型系統可以執行完整場景集的多個副本,例如,具有 448 個硬體執行緒的系統可以併發執行五個完整集的例項。為了實現這一點

kvm.sh --cpus 448 --configs '5*CFLIST'

或者,這樣的系統可以執行單個八 CPU 場景的 56 個併發例項

kvm.sh --cpus 448 --configs '56*TREE04'

或每個八 CPU 場景的 28 個併發例項

kvm.sh --cpus 448 --configs '28*TREE03 28*TREE04'

當然,每個併發例項都會使用記憶體,這可以使用 --memory 引數進行限制,該引數預設為 512M。較小的記憶體值可能需要使用下面討論的 --bootargs 引數停用回撥泛洪測試。

有時額外的除錯很有用,在這種情況下,可以使用 kvm.sh 的 --kconfig 引數,例如,--kconfig 'CONFIG_RCU_EQS_DEBUG=y'。此外,還有 --gdb、--kasan 和 --kcsan 引數。請注意,--gdb 將您限制為每次 kvm.sh 執行一個場景,並且要求您開啟另一個視窗,從中按照指令碼的指示執行 gdb

也可以提供核心啟動引數,例如,控制 rcutorture 的模組引數。例如,要測試對 RCU 的 CPU 停頓警告程式碼的更改,請使用 “--bootargs ‘rcutorture.stall_cpu=30’”。這當然會導致指令碼報告失敗,即導致 RCU CPU 停頓警告。如上所述,減少記憶體可能需要停用 rcutorture 的回撥泛洪測試

kvm.sh --cpus 448 --configs '56*TREE04' --memory 128M \
        --bootargs 'rcutorture.fwd_progress=0'

有時只需要完整的核心構建集。這就是 --buildonly 引數的作用。

--duration 引數可以覆蓋 30 分鐘的預設執行時間。例如,--duration 2d 將執行兩天,--duration 3h 將執行三個小時,--duration 5m 將執行五分鐘,--duration 45s 將執行 45 秒。最後一個對於追蹤罕見的啟動時故障很有用。

最後,--trust-make 引數允許每個核心構建重用它可以從上一個核心構建中重用的內容。請注意,如果沒有 --trust-make 引數,您的 tags 檔案可能會被破壞。

kvm.sh 指令碼的原始碼中記錄了其他更神秘的引數。

如果執行包含失敗,則構建時和執行時失敗的次數將在 kvm.sh 輸出的末尾列出,您確實應該將其重定向到檔案。每次執行的構建產品和控制檯輸出都儲存在 tools/testing/selftests/rcutorture/res 中,位於帶有時間戳的目錄中。可以將給定目錄提供給 kvm-find-errors.sh,以便讓它迴圈瀏覽錯誤摘要和完整錯誤日誌。例如

tools/testing/selftests/rcutorture/bin/kvm-find-errors.sh \
        tools/testing/selftests/rcutorture/res/2020.01.20-15.54.23

但是,直接訪問檔案通常更方便。與執行中所有場景相關的檔案位於頂級目錄(在上面的示例中為 2020.01.20-15.54.23)中,而每個場景的檔案位於以場景命名的子目錄中(例如,“TREE04”)。如果給定場景執行多次(如在 “--configs ‘56*TREE04’” 中),則與該場景的第二次和後續執行相對應的目錄包括一個序列號,例如,“TREE04.2”、“TREE04.3”,依此類推。

頂級目錄中最常用的檔案是 testid.txt。如果測試在 git 儲存庫中執行,則此檔案包含測試的提交以及 diff 格式的任何未提交的更改。

每個場景執行目錄中最常用的檔案是

.config

此檔案包含 Kconfig 選項。

Make.out

此檔案包含特定場景的構建輸出。

console.log

此檔案包含特定場景的控制檯輸出。一旦核心啟動,就可以檢查此檔案,但如果構建失敗,則該檔案可能不存在。

vmlinux

此檔案包含核心,這對於 objdump 和 gdb 等工具很有用。

還有許多其他檔案可用,但使用頻率較低。許多檔案旨在用於除錯 rcutorture 本身或其指令碼。

在 v5.4 中,使用預設場景整合功執行會在 12 CPU 系統的執行結束時生成以下摘要

SRCU-N ------- 804233 GPs (148.932/s) [srcu: g10008272 f0x0 ]
SRCU-P ------- 202320 GPs (37.4667/s) [srcud: g1809476 f0x0 ]
SRCU-t ------- 1122086 GPs (207.794/s) [srcu: g0 f0x0 ]
SRCU-u ------- 1111285 GPs (205.794/s) [srcud: g1 f0x0 ]
TASKS01 ------- 19666 GPs (3.64185/s) [tasks: g0 f0x0 ]
TASKS02 ------- 20541 GPs (3.80389/s) [tasks: g0 f0x0 ]
TASKS03 ------- 19416 GPs (3.59556/s) [tasks: g0 f0x0 ]
TINY01 ------- 836134 GPs (154.84/s) [rcu: g0 f0x0 ] n_max_cbs: 34198
TINY02 ------- 850371 GPs (157.476/s) [rcu: g0 f0x0 ] n_max_cbs: 2631
TREE01 ------- 162625 GPs (30.1157/s) [rcu: g1124169 f0x0 ]
TREE02 ------- 333003 GPs (61.6672/s) [rcu: g2647753 f0x0 ] n_max_cbs: 35844
TREE03 ------- 306623 GPs (56.782/s) [rcu: g2975325 f0x0 ] n_max_cbs: 1496497
CPU count limited from 16 to 12
TREE04 ------- 246149 GPs (45.5831/s) [rcu: g1695737 f0x0 ] n_max_cbs: 434961
TREE05 ------- 314603 GPs (58.2598/s) [rcu: g2257741 f0x2 ] n_max_cbs: 193997
TREE07 ------- 167347 GPs (30.9902/s) [rcu: g1079021 f0x0 ] n_max_cbs: 478732
CPU count limited from 16 to 12
TREE09 ------- 752238 GPs (139.303/s) [rcu: g13075057 f0x0 ] n_max_cbs: 99011

重複執行

假設您正在追蹤一個罕見的啟動時故障。雖然您可以使用 kvm.sh,但這樣做會在每次執行時重建核心。如果您需要(例如)1,000 次執行才能確信已修復該錯誤,那麼這些毫無意義的重建可能會變得非常煩人。

這就是 kvm-again.sh 存在的原因。

假設之前的 kvm.sh 執行將其輸出留在該目錄中

tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28

然後可以重新執行此執行,而無需重建,如下所示

kvm-again.sh tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28

可以覆蓋原始執行的一些 kvm.sh 引數,其中最值得注意的是 --duration 和 --bootargs。例如

kvm-again.sh tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28 \
        --duration 45s

將重新執行之前的測試,但僅執行 45 秒,從而有助於追蹤上述罕見的啟動時故障。

分散式執行

儘管 kvm.sh 非常有用,但其測試僅限於單個系統。使用您最喜歡的框架在您的 5 個系統上執行(例如)5 個 kvm.sh 例項並不難,但這很可能會不必要地重建核心。此外,手動將所需的 rcutorture 場景分發到可用系統可能非常繁瑣且容易出錯。

這就是 kvm-remote.sh 指令碼存在的原因。

如果以下命令有效

ssh system0 date

並且如果它也適用於 system1、system2、system3、system4 和 system5,並且所有這些系統都有 64 個 CPU,您可以鍵入

kvm-remote.sh "system0 system1 system2 system3 system4 system5" \
        --cpus 64 --duration 8h --configs "5*CFLIST"

這將在本地系統上構建每個預設場景的核心,然後將每個場景的五個例項分散在列出的系統上,每個場景執行八個小時。在執行結束時,結果將被收集、記錄和列印。kvm.sh 將接受的大多數引數都可以傳遞給 kvm-remote.sh,但系統列表必須排在第一位。

kvm.sh --dryrun scenarios 引數對於計算可以在一組系統中一批執行多少個場景很有用。

您還可以以類似於 kvm.sh 的方式重新執行之前的遠端執行

kvm-remote.sh “system0 system1 system2 system3 system4 system5”

tools/testing/selftests/rcutorture/res/2022.11.03-11.26.28-remote --duration 24h

在這種情況下,可以在舊執行結果目錄的路徑名之後提供大多數 kvm-again.sh 引數。