Linux

dd 正在全速執行,但我只看到 20% 的磁碟使用率。為什麼?

  • July 11, 2020
  1. sudo dd if=/dev/sda of=/dev/null bs=1M iflag=direct
  2. atopsar -d 5 # in a second terminal
  3. 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=directdd使用大約 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_tickspart_stat_show()中使用,為“欄位 10 - # of milliseconds 花在執行 I/O 上的時間”提供核心 IO 統計資訊。)

這很好地解釋了我的結果。在 Fedora 核心配置中,“ jiffy ”是 1 毫秒。我預計送出的大型讀取 IOdd可能會等待超過一兩個 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

這個舊核心預設使用傳統的單隊列塊層和cfqIO 調度程序。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>

引用自:https://unix.stackexchange.com/questions/517132