dd
正在全速執行,但我只看到 20% 的磁碟使用率。為什麼?
sudo dd if=/dev/sda of=/dev/null bs=1M iflag=direct
atopsar -d 5 # in a second terminal
top # in a third terminal
結果來自
atopsar
:19:18:32 disk busy read/s KB/read writ/s KB/writ avque avserv _dsk_ ... 19:16:50 sda 18% 156.5 1024.0 0.0 0.0 5.0 1.15 ms 19:16:55 sda 18% 156.3 1024.0 0.0 0.0 4.9 1.15 ms ...
為什麼報告的磁碟使用率(“忙碌”)遠低於 100%?
根據
top
,該dd
程序僅使用 3% 或更少的 CPU。 還提供了系統 CPU 的硬體和軟體中斷 (和) 使用情況top
的總體報告,顯示低於 1%。我有四個 CPU(2 個核心,每個核心有 2 個執行緒)。hi``si
/dev/sda
是SATA硬碟。它不是 SSD,甚至不是混合 SSHD 驅動器。它的讀取速度不能超過每秒 150 兆字節 :-)。所以這部分結果是有意義的:156 read/s * 1024 KB/read = 156 MB/s核心版本是
5.0.9-200.fc29.x86_64
(Fedora Workstation 29)。IO 調度程序是mq-deadline
. 從核心版本 5.0 開始,Fedora 使用多隊列塊層。因為單個隊列塊層已被刪除:-)。我相信磁碟使用率數據是根據核心 iostat 欄位之一計算得出
atopsar -d
的。連結的文件提到“欄位 10 - 花費在 I/O 上的毫秒數”。還有一個更詳細的定義,雖然我不確定它提到的功能是否仍然存在於多隊列塊層中。據我所知,兩者都使用通用程式碼來讀取這個欄位 10. (我相信這個欄位也被//使用)atop``atopsar -d``atop``sar -d``iostat -x``mxiostat.py
附加測試
變體 2:更改為
bs=512k
,但保留iflag=direct
。
dd if=/dev/sda of=/dev/null bs=512k iflag=direct
19:18:32 disk busy read/s KB/read writ/s KB/writ avque avserv _dsk_ ... 19:18:00 sda 35% 314.0 512.0 0.0 0.0 2.1 1.12 ms 19:18:05 sda 35% 313.6 512.0 0.2 4.0 2.1 1.11 ms
變體 3:使用
bs=1M
,但刪除iflag=direct
。dd
使用大約 10% 的 CPU 和 35% 的磁碟。
dd if=/dev/sda of=/dev/null bs=1M
19:18:32 disk busy read/s KB/read writ/s KB/writ avque avserv _dsk_ ... 19:21:47 sda 35% 242.3 660.2 0.0 0.0 5.4 1.44 ms 19:21:52 sda 31% 232.3 667.8 0.0 0.0 9.5 1.33 ms
如何重現這些結果 - 基本細節
當心最後的測試,即在
dd
沒有的情況下執行iflag=direct
這有點像豬。我看到它凍結系統(滑鼠游標)十秒鐘或更長時間。即使我禁用了交換。(測試用buff/cache填充你的 RAM 。它正在填充非活動 LRU 列表。我認為周轉相對較快地驅逐非活動記憶體頁面。同時,磁碟忙於順序讀取,因此在需要時需要更長的時間將某些內容分頁。這可能會變得多麼糟糕,這可能取決於核心最終是否也翻轉了活動 LRU 列表,或者將其縮小太多。即目前的“多種不同算法的混搭效果如何,並進行了一些修改捕捉極端情況和各種優化”適用於您的情況)。
第一次測試的確切結果很難重現。
有時,
KB/read
顯示為512
而不是1024
. 在這種情況下,其他結果看起來更像bs=512k
. 包括它顯示大約 35% 的磁碟使用率,而不是大約 20%。無論哪種情況,我的問題都成立。如果您想了解這種行為,請參閱此處:為什麼我的 IO 請求的大小被限制為大約 512K?
這是核心版本 5.0 更改的結果:
塊:刪除 part_round_stats 並切換到不太精確的計數
我們要轉換為 per-cpu in_flight 計數器。
函式 part_round_stats 需要每 jiffy 的 in_flight 計數器,每 jiffy 對所有 percpu 變數求和太昂貴,所以必須刪除它。part_round_stats 用於計算兩個計數器 - time_in_queue 和 io_ticks。
time_in_queue 可以在沒有 part_round_stats 的情況下計算,方法是在 I/O 結束時添加 I/O 的持續時間(該值幾乎與先前計算的值一樣精確,除了正在進行的 I/O 的時間不計算在內)。
io_ticks 可以通過在 I/O 開始或結束並且 jiffies 值發生變化時增加值來近似。如果 I/O 佔用的時間少於一瞬間,則該值與先前計算的值一樣精確。如果 I/O 佔用的時間超過一瞬間,io_ticks 可能會落後於先前計算的值。
(
io_ticks
在part_stat_show()中使用,為“欄位 10 - # of milliseconds 花在執行 I/O 上的時間”提供核心 IO 統計資訊。)這很好地解釋了我的結果。在 Fedora 核心配置中,“ jiffy ”是 1 毫秒。我預計送出的大型讀取 IO
dd
可能會等待超過一兩個 jiffies。特別是在我的系統上,它使用老式的機械硬碟。當我回到之前的核心系列 4.20.x 時,它顯示了正確的磁碟使用率:
$ uname -r 4.20.15-200.fc29.x86_64 $ atopsar -d 5 ... 13:27:19 disk busy read/s KB/read writ/s KB/writ avque avserv _dsk_ 13:28:49 sda 98% 149.4 1024.0 13.0 5.3 2.2 6.04 ms 13:28:54 sda 98% 146.0 1024.0 7.2 5.7 1.5 6.38 ms
這個舊核心預設使用傳統的單隊列塊層和
cfq
IO 調度程序。deadline
使用IO 調度器的結果也是一樣的。更新:自核心 5.7 起,此近似值已調整。問題中的命令再次顯示 100% 磁碟使用率。對於一些更複雜的工作負載(儘管我還沒有註意到),預計新的近似值會被分解。
block/diskstats:對慢速磁碟更準確的 io_ticks 近似值
如果 jiffies 計數器發生變化,目前 io_ticks 是通過在請求的每個開始和結束時添加一個來近似的。這非常適用於短於一瞬間的請求,或者如果其中一個請求在每個瞬間開始/結束。
如果磁碟一次只執行一個請求並且它們比兩個 jiffies 長,則只計算第一個和最後一個 jiffies。
修復很簡單:在請求結束時添加自上次更新以來傳遞的 io_ticks jiffies 而不是一個 jiffy。
範例:普通 HDD 在 12ms 左右執行隨機讀取 4k 請求。
fio --name=test --filename=/dev/sdb --rw=randread --direct=1 --runtime=30 &
iostat -x 10 sdb
注意 iostat 的 “%util” 8,43% -> 99,99% 在更新檔之前/之後的變化:
前:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sdb 0,00 0,00 82,60 0,00 330,40 0,00 8,00 0,96 12,09 12,09 0,00 1,02 8,43
後:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sdb 0,00 0,00 82,50 0,00 330,00 0,00 8,00 1,00 12,10 12,10 0,00 12,12 99,99
現在 io_ticks 不會失去請求開始和結束之間的時間,但是對於 queue-depth > 1,相鄰開始之間的一些 I/O 時間可能會失去。
對於負載估計,“%util”不如平均隊列長度有用,但它清楚地顯示了磁碟隊列完全為空的頻率。
修復:5b18b5a(“阻止:刪除 part_round_stats 並切換到不太精確的計數”)
簽名人:Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
審核人:雷明 <ming.lei@redhat.com>
簽名人-off-by: Jens Axboe <axboe@kernel.dk>