“dd”中的“bs”选项真的能提高速度吗?

Dam*_*lli 77 linux kernel dd disk-image

时不时地,我被告知要提高“dd”的速度,我应该仔细选择合适的“块大小”。

即使在这里,在 ServerFault 上,其他人也写道...最佳块大小取决于硬件...(iain)或“ ...完美的大小将取决于您的系统总线、硬盘驱动器控制器、特定驱动器本身,以及每个驱动程序......(克里斯 - s)

由于我的感觉有点不同(顺便说一句:我认为深度调整 bs 参数所需的时间远高于获得的增益,在节省时间方面,并且默认是合理的),今天我刚去了通过一些快速而肮脏的基准测试。

为了降低外部影响,我决定阅读:

  • 从外部 MMC 卡
  • 从内部分区

和:

  • 已卸载相关文件系统
  • 将输出发送到 /dev/null 以避免与“写入速度”相关的问题;
  • 避免 HDD 缓存的一些基本问题,至少在涉及 HDD 时。

在下表中,我报告了我的发现,读取了具有不同“bs”值的 1GB 数据(您可以在此消息的末尾找到原始数字):

在此处输入图片说明

基本上得出的结论是:

  • MMC:使用 bs=4(是的!4 字节),我达到了 12MB/s 的吞吐量。我从 bs=5 及以上得到的最大 14.2/14.3 的值并不那么遥远;

  • 硬盘:bs=10 我达到了 30 MB/s。肯定低于默认 bs=512 获得的 95.3 MB,但......也很重要。

此外,很明显,CPU 系统时间与 bs 值成反比(但这听起来很合理,因为 bs 越低,dd 生成的系统调用数量就越高)。

说了以上所有,现在的问题是:有人可以解释(内核黑客?)这种吞吐量所涉及的主要组件/系统是什么,以及是否真的值得努力指定高于默认值的 bs?


MMC 案例 - 原始数字

bs=1M

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=1M count=1000
1000+0 record dentro
1000+0 record fuori
1048576000 byte (1,0 GB) copiati, 74,1239 s, 14,1 MB/s

real    1m14.126s
user    0m0.008s
sys     0m1.588s
Run Code Online (Sandbox Code Playgroud)

bs=1k

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=1k count=1000000
1000000+0 record dentro
1000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 72,7795 s, 14,1 MB/s

real    1m12.782s
user    0m0.244s
sys     0m2.092s
Run Code Online (Sandbox Code Playgroud)

bs=512

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=512 count=2000000
2000000+0 record dentro
2000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 72,867 s, 14,1 MB/s

real    1m12.869s
user    0m0.324s
sys     0m2.620s
Run Code Online (Sandbox Code Playgroud)

bs=10

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=10 count=100000000
100000000+0 record dentro
100000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 70,1662 s, 14,3 MB/s

real    1m10.169s
user    0m6.272s
sys     0m28.712s
Run Code Online (Sandbox Code Playgroud)

bs=5

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=5 count=200000000
200000000+0 record dentro
200000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 70,415 s, 14,2 MB/s

real    1m10.417s
user    0m11.604s
sys     0m55.984s
Run Code Online (Sandbox Code Playgroud)

bs=4

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=4 count=250000000
250000000+0 record dentro
250000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 80,9114 s, 12,4 MB/s

real    1m20.914s
user    0m14.436s
sys     1m6.236s
Run Code Online (Sandbox Code Playgroud)

bs=2

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=2 count=500000000
500000000+0 record dentro
500000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 161,974 s, 6,2 MB/s

real    2m41.976s
user    0m28.220s
sys     2m13.292s
Run Code Online (Sandbox Code Playgroud)

bs=1

root@iMac-Chiara:/tmp# time dd if=/dev/sdc of=/dev/null bs=1 count=1000000000
1000000000+0 record dentro
1000000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 325,316 s, 3,1 MB/s

real    5m25.318s
user    0m56.212s
sys     4m28.176s
Run Code Online (Sandbox Code Playgroud)

硬盘盒 - 原始数字

bs=1

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=1 count=1000000000
1000000000+0 record dentro
1000000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 341,461 s, 2,9 MB/s

real    5m41.463s
user    0m56.000s
sys 4m44.340s
Run Code Online (Sandbox Code Playgroud)

bs=2

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=2 count=500000000
500000000+0 record dentro
500000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 164,072 s, 6,1 MB/s

real    2m44.074s
user    0m28.584s
sys 2m14.628s
Run Code Online (Sandbox Code Playgroud)

bs=4

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=4 count=250000000
250000000+0 record dentro
250000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 81,471 s, 12,3 MB/s

real    1m21.473s
user    0m14.824s
sys 1m6.416s
Run Code Online (Sandbox Code Playgroud)

bs=5

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=5 count=200000000
200000000+0 record dentro
200000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 66,0327 s, 15,1 MB/s

real    1m6.035s
user    0m11.176s
sys 0m54.668s
Run Code Online (Sandbox Code Playgroud)

bs=10

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=10 count=100000000
100000000+0 record dentro
100000000+0 record fuori
1000000000 byte (1,0 GB) copiati, 33,4151 s, 29,9 MB/s

real    0m33.417s
user    0m5.692s
sys 0m27.624s
Run Code Online (Sandbox Code Playgroud)

bs=512(偏移读取,避免缓存)

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=512 count=2000000 skip=6000000
2000000+0 record dentro
2000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 10,7437 s, 95,3 MB/s

real    0m10.746s
user    0m0.360s
sys 0m2.428s
Run Code Online (Sandbox Code Playgroud)

bs=1k(偏移读取,避免缓存)

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=1k count=1000000 skip=6000000
1000000+0 record dentro
1000000+0 record fuori
1024000000 byte (1,0 GB) copiati, 10,6561 s, 96,1 MB/s

real    0m10.658s
user    0m0.164s
sys 0m1.772s
Run Code Online (Sandbox Code Playgroud)

bs=1k(偏移读取,避免缓存)

root@iMac-Chiara:/tmp# time dd if=/dev/sda3 of=/dev/null bs=1M count=1000 skip=7000
1000+0 record dentro
1000+0 record fuori
1048576000 byte (1,0 GB) copiati, 10,7391 s, 97,6 MB/s

real    0m10.792s
user    0m0.008s
sys 0m1.144s
Run Code Online (Sandbox Code Playgroud)

小智 32

您所做的只是读取速度测试。如果您实际上是将块复制到另一台设备,则在另一台设备正在接受您要写入的数据时读取暂停,当发生这种情况时,您可能会遇到读取设备上的旋转延迟问题(如果它是硬盘)等等从 HDD 读取 1M 块的速度通常要快得多,因为您不太经常遇到旋转延迟。

我知道当我复制硬盘时,通过指定bs=1M比使用bs=4k或默认获得更快的速度。我说的是速度提高了 30% 到 300%。除非您每天都这样做,否则无需将其调整为绝对最佳。但是选择比默认值更好的东西可以减少执行时间。

当您真正使用它时,请尝试几个不同的数字,并向该dd过程发送一个SIGUSR1信号,让它发出状态报告,这样您就可以看到它的进展情况。

? killall -SIGUSR1 dd
1811+1 records in
1811+1 records out
1899528192 bytes (1.9 GB, 1.8 GiB) copied, 468.633 s, 4.1 MB/s
Run Code Online (Sandbox Code Playgroud)

  • 如果有人对 Mac 终端感兴趣,检查状态的 SIGUSR1 信号是 CTRL + t (2认同)

Mat*_*Ife 10

关于内部硬盘,至少 - 当您从设备读取数据时,块层至少必须检索一个 512 字节的扇区。

因此,在处理 1 字节读取时,您实际上只是在扇区对齐字节检索上从磁盘读取。剩余的 511 次由缓存提供。

您可以如下证明这一点,在这个例子中sdb是一个感兴趣的磁盘:

# grep sdb /proc/diskstats
8      16 sdb 767 713 11834 6968 13710 6808 12970792 6846477 0 76967 6853359
...
# dd if=/dev/sdb of=/dev/null bs=1 count=512
512+0 records in
512+0 records out
512 bytes (512 B) copied, 0.0371715 s, 13.8 kB/s
# grep sedb /proc/diskstats
8      16 sdb 768 713 11834 6968 13710 6808 12970792 6846477 0 76967 6853359
...
Run Code Online (Sandbox Code Playgroud)

尽管您请求了 1 个字节的读取,但第四列(对读取进行计数)表示仅发生了 1 次读取。这是预期行为,因为此设备(SATA 2 磁盘)必须至少返回其扇区大小。内核只是缓存整个扇区。

在这些大小请求中起作用的最大因素是发出读取或写入系统调用的开销。事实上,发出 < 512 的调用是低效的。非常大的读取需要更少的系统调用,代价是使用更多的内存来完成它。

4096 通常是读取的“安全”数字,因为:

  • 当读取缓存(默认)时,页面为 4k。用 < 4k 读取填充页面比保持读取和页面大小相同更复杂。
  • 大多数文件系统块大小设置为 4k。
  • 它不是一个足够小的数字(也许对于 SSD 现在是这样)导致系统调用开销,但不是一个足够大的数字来消耗大量内存。