dd产生的是32 MB随机文件,而不是1 GB


50

我想产生一个1 GB的随机文件,因此我使用了以下命令。

dd if=/dev/urandom of=output bs=1G count=1

但是,每次我启动此命令时,我都会得到一个32 MB的文件:

<11:58:40>$ dd if=/dev/urandom of=output bs=1G count=1
0+1 records in
0+1 records out
33554431 bytes (34 MB, 32 MiB) copied, 0,288321 s, 116 MB/s

怎么了?

编辑:

多亏了本主题中的出色答案,我提供了一个解决方案,该解决方案读取32个大32 MB的块,即1GB:

dd if=/dev/urandom of=output bs=32M count=32

给出了其他解决方案,该解决方案直接读取1 GB的内存,然后再写入磁盘。此解决方案占用大量内存,因此不推荐使用:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock

3
恕我直言,我认为根本没有很多有效的用例dd。我会使用headcat或者rsync几乎总是使用它。您的问题是否是替代方法通常更安全的原因之一。
巴库里

@Bakuriu-同样,如果您只想生成一个全为零的文件(或者您根本不在乎其中的内容),请使用truncate。它快得多。
Konrad Gajewski

@KonradGajewski FYI截断试图制作一个稀疏文件(如果有的话)
Xen2050

5
如果head没有POSIX中没有的-c选项,@ Bakuriu 无法执行此任务。我不知道哪个版本可以解决此问题。是一个完全非标准的实用程序。那里既不在那里;也没有那里。略过其手册页,我也看不到它如何解决此问题。catrsync
卡兹(Kaz)

从技术上讲,/dev/urandom也不在POSIX中...
grawity

Answers:


94

bs,缓冲区大小,是指dd完成的单个read()调用的大小。

(例如,bs=1M count=1bs=1k count=1k都将产生一个1 MiB文件,但是第一个版本将在一个步骤中完成,而第二个版本将在1024个小块中完成。)

常规文件几乎可以以任何大小的缓冲区读取(只要该缓冲区适合RAM),但是设备和“虚拟”文件通常非常接近单个调用,并且对它们每次生成多少数据有一定的限制。 read()调用。

对于/dev/urandom,此限制是在drivers / char / random.c的urandom_read()中定义的:

#define ENTROPY_SHIFT 3

static ssize_t
urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
    nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
    ...
}

这意味着每次调用该函数时,它将请求的大小限制为33554431字节。

默认情况下,与大多数其他工具不同,dd收到的数据少于请求的数量时将不重试-您获得了32 MiB,仅此而已。(要使其自动重试,就像在Kamil的回答中一样,您需要指定iflag=fullblock。)


还要注意,“单个read()的大小”意味着整个缓冲区必须立即容纳在内存中,因此大块大小也对应于dd的大内存使用量。

这都是毫无意义的,因为在超过〜16–32 MiB块时,您通常不会获得任何性能–随机数生成器在这里,系统调用并不是最慢的部分。

因此,为简单起见,只需使用即可head -c 1G /dev/urandom > output


7
“ ...在超过〜16-32 MiB块时,通常不会获得任何性能” -根据我的经验,在64-128 字节以上时,您往往不会获得太多收益,甚至会失去性能。到那时,您的系统调用成本收益逐渐减少,并且缓存争用开始发挥作用。
marcelm

3
@marcelm我已经帮助构建了高性能系统,随着块大小增加到1-2 MB块,在某些情况下达到8 MB左右,IO性能将得到改善。每个LUN。随着使用多个并行LUN构建文件系统,要获得最佳性能,意味着要使用多个IO线程,每个线程执行1 MB +的块。持续的IO速率超过1 GB /秒。而且这些都是旋转磁盘,因此我可以看到高性能的SSD阵列随着块大小增加到16甚至32 MB块而吞噬或生成数据的速度越来越快。容易。甚至更大。
Andrew Henle

4
我将明确指出这iflag=fullblockPOSIX dd实用程序的GNU扩展。由于该问题并未指定Linux,因此我认为应该明确指出使用特定于Linux的扩展,以免将来的读者试图解决非Linux系统上的类似问题。
安德鲁·亨利

6
@AndrewHenle啊,有趣!我dd在机器上进行了快速测试,块大小从1k到512M。从Intel 750 SSD读取数据时,在2MiB数据块上可获得最佳性能(约1300MiB / s),与您的结果大致相符。较大的块大小既无帮助也无阻碍。从读取/dev/zero,最佳性能(接近20GiB / s)为64KiB和128KiB块;这两个小更大的块性能下降,大致符合我之前的评论。底线:您实际情况的基准。当然,我们两个人都没有基准/dev/random:P
marcelm

3
@ Xen2050我做了一些更快速的测试,它看起来dd更快。快速跟踪显示head使用8KiB读取和两次4KiB写入,这很有趣(Debian 9.6 / Linux 4.8上的GNU coreutils 8.26)。head速度确实在dd bs=4k和之间dd bs=8khead与相比,速度降低了〜40%,与相比dd if=/dev/zero bs=64k降低了〜25%dd if=/dev/nvme0n1 bs=2M。读取的内容/dev/zero当然更多地受CPU限制,但对于SSD I / O队列也起作用。比我预期的要大得多。
marcelm

21

dd除非指定,否则可能小于ibs(注:同时bs指定ibsobsiflag=fullblock0+1 records in表示已读取0完整块和1部分块。但是,任何完整或部分块都会增加计数器。

我不知道使dd读取的块小1G于此特定情况的确切机制。我猜想任何块都会在写入之前被读取到内存中,因此内存管理可能会干扰(但这只是一个猜测)。编辑:此并发答案说明了使dd读取的块小1G于此特定情况的机制。

无论如何,我不建议这么大bs。我会用bs=1M count=1024。最重要的是:没有iflag=fullblock 任何读取尝试,读取的内容可能少于ibs(除非ibs=1,我认为,这效率很低)。

因此,如果您需要读取确切数量的数据,请使用iflag=fullblockiflagPOSIX不需要注释,您dd可能不支持它。根据这个答案 ibs=1,可能是唯一的POSIX方式来读取确切数目的字节。当然,如果您进行更改,ibs则需要重新计算count。在您的情况下,降低ibs32M或更低将可能解决该问题,即使没有iflag=fullblock

在我的Kubuntu中,我将像这样修复您的命令:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.