dd está produzindo um arquivo aleatório de 32 MB em vez de 1 GB

50

Como eu queria produzir um arquivo aleatório de 1 GB, usei o seguinte comando.

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

Mas, em vez disso, sempre que inicio este comando, recebo um arquivo de 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

O que está errado?

EDITAR:

Graças a ótimas respostas neste tópico, eu vim com uma solução com 32 pedaços de 32 MB de tamanho, o que perfaz 1 GB:

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

Outra solução foi fornecida: lê 1 GB diretamente na memória e depois grava no disco. Esta solução consome muita memória, portanto não é preferida:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock
Trismegistos
fonte
3
IMHO Acho que não existem muitos casos de uso válidos dd. Eu usaria head, catou rsyncem seu lugar quase sempre. E sua pergunta se uma das razões pelas quais as alternativas são geralmente mais seguras.
Bakuriu
@ Bakuriu - também, se você quiser apenas produzir um arquivo cheio de zeros (ou melhor, você não se importa com o que está dentro dele), use truncate. É muito mais rápido.
Konrad Gajewski
@KonradGajewski tentativas FYI truncar fazer um arquivo esparso (se o que importa)
Xen2050
5
O @Bakuriu headnão pode executar esta tarefa sem a -copção que não está no POSIX . Não conheço nenhuma versão catque possa resolver isso. rsyncé um utilitário completamente fora do padrão. Isso não está aqui nem ali; folheando sua página de manual, também não vejo como ele pode resolver esse problema.
Kaz
Tecnicamente, /dev/urandomnão está na POSIX ou ...
grawity

Respostas:

92

bs, o tamanho do buffer, significa o tamanho de uma única chamada read () feita por dd.

(Por exemplo, ambos bs=1M count=1e bs=1k count=1kresultará em um arquivo 1 MiB, mas a primeira versão o fará em uma única etapa, enquanto a segunda fará em 1024 pequenos pedaços.)

Os arquivos regulares podem ser lidos em praticamente qualquer tamanho de buffer (desde que esse buffer caiba na RAM), mas os dispositivos e arquivos "virtuais" geralmente trabalham muito perto das chamadas individuais e têm alguma restrição arbitrária da quantidade de dados que eles produzirão por chamada read ().

Para /dev/urandom, este limite é definido em urandom_read () em drivers / char / random.c :

#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));
    ...
}

Isso significa que toda vez que a função for chamada, ela limitará o tamanho solicitado a 33554431 bytes.

Por padrão, diferentemente da maioria das outras ferramentas, o dd não tentará novamente depois de receber menos dados do que o solicitado - você obtém o 32 MiB e é isso. (Para fazê-lo tentar novamente automaticamente, como na resposta de Kamil, você precisará especificar iflag=fullblock.)


Observe também que "o tamanho de uma única leitura ()" significa que todo o buffer deve caber na memória de uma só vez; portanto, tamanhos enormes de blocos também correspondem ao uso massivo de memória por dd .

E é tudo inútil, porque você geralmente não obtém desempenho acima de 16 a 32 blocos MiB - os syscalls não são a parte mais lenta aqui, o gerador de números aleatórios é.

Portanto, para simplificar, basta usar head -c 1G /dev/urandom > output.

gravidade
fonte
7
"... você geralmente não obtém desempenho superior a ~ 16–32 blocos MiB" - Na minha experiência, você tende a não ganhar muito ou até a perder desempenho acima de 64 a 128 quilos de bytes. Nesse ponto, você está bem com os retornos decrescentes do custo da syscall e a contenção do cache começa a desempenhar um papel.
marcelm
3
@marcelm Ajudei a arquitetar sistemas de alto desempenho em que o desempenho de IO melhorava à medida que o tamanho do bloco aumentava para 1-2 MB e, em alguns casos, até 8 MB. Por LUN. E como os sistemas de arquivos foram construídos usando vários LUNs paralelos, para obter o melhor desempenho, use vários threads para E / S, cada um fazendo blocos de 1 MB +. As taxas de IO sustentadas foram superiores a 1 GB / s. E todos eram discos giratórios, para que eu possa ver matrizes de alto desempenho de SSDs engolindo ou gerando dados cada vez mais rápido à medida que o tamanho do bloco aumenta para 16 ou até 32 MB. Facilmente. Talvez até maior.
Andrew Henle
4
Observarei explicitamente que iflag=fullblocké uma extensão GNU do ddutilitário POSIX . Como a pergunta não especifica o Linux, acho que o uso de extensões específicas do Linux provavelmente deve ser explicitamente observado, para que algum leitor futuro que tente resolver um problema semelhante em um sistema não-Linux seja confundido.
Andrew Henle
6
@AndrewHenle Ah, interessante! Fiz um teste rápido ddna minha máquina, com tamanhos de bloco de 1k a 512M. Lendo de um SSD Intel 750, o desempenho ideal (cerca de 1300MiB / s) foi alcançado em blocos de 2MiB, correspondendo aproximadamente aos seus resultados. Tamanhos maiores de blocos não ajudaram nem atrapalharam. Lendo de /dev/zero, o desempenho ideal (quase 20GiB / s) foi nos blocos de 64KiB e 128KiB; blocos menores e maiores diminuíram o desempenho, correspondendo aproximadamente ao meu comentário anterior. Conclusão: referência para a sua situação real. E, é claro, nenhum de nós /dev/random
comparou
3
@ Xen2050 Fiz alguns testes mais rápidos e parece que ddé mais rápido. Uma rápida análise mostrou que headusa 8KiB lê e duas gravações 4KiB, o que é interessante (GNU coreutils 8.26 no Debian 9.6 / Linux 4.8). headvelocidades são de fato em algum lugar entre dd bs=4ke dd bs=8k. headas velocidades caíram ~ 40% em comparação com dd if=/dev/zero bs=64ke ~ 25% em comparação com dd if=/dev/nvme0n1 bs=2M. As leituras /dev/zerode, obviamente, são mais limitadas à CPU, mas para as filas de E / S SSD também desempenham um papel. É uma diferença maior do que eu esperava.
marcelm
21

ddpode ler menos que ibs(nota: bsespecifica ambos ibse obs), a menos que iflag=fullblockseja especificado. 0+1 records inindica que os 0blocos completos e 1parciais foram lidos. No entanto, qualquer bloqueio total ou parcial aumenta o contador.

Eu não sei o mecanismo exato que faz ddler um bloco que é menor do que 1Gneste caso particular. Eu acho que qualquer bloco é lido na memória antes de ser gravado, portanto, o gerenciamento de memória pode interferir (mas isso é apenas um palpite). Editar: esta resposta simultânea explica o mecanismo que torna a ddleitura de um bloco menor do que 1Gnesse caso específico.

Enfim, eu não recomendo tão grande bs. Eu usaria bs=1M count=1024. O mais importante é: sem iflag=fullblock nenhuma tentativa de leitura, a leitura pode ser menor que ibs(a menos que ibs=1eu ache que isso é bastante ineficiente).

Portanto, se você precisar ler uma quantidade exata de dados, use iflag=fullblock. Nota iflagnão é requerida pelo POSIX, ddtalvez você não a suporte. De acordo com esta resposta, ibs=1 provavelmente é a única maneira POSIX de ler um número exato de bytes. Obviamente, se você alterar ibs, será necessário recalcular o count. No seu caso, diminuir ibspara 32Mou menos provavelmente resolverá o problema, mesmo sem ele iflag=fullblock.

No meu Kubuntu, eu corrigia seu comando assim:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock
Kamil Maciorowski
fonte