dd sta producendo un file casuale da 32 MB anziché 1 GB


50

Volevo produrre un file casuale da 1 GB, quindi ho usato il seguente comando.

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

Ma invece ogni volta che lancio questo comando ottengo un file da 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

Che c'è?

MODIFICARE:

Grazie alle ottime risposte in questo argomento, sono arrivato con una soluzione che legge 32 blocchi di 32 MB di larghezza che rende 1 GB:

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

È stata fornita un'altra soluzione che legge 1 GB direttamente nella memoria e quindi scrive sul disco. Questa soluzione richiede molta memoria, quindi non è preffered:

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

3
IMHO Non credo ci siano molti casi d'uso validi per ddniente. Userei head, cato rsyncal suo posto quasi sempre. E la tua domanda se uno dei motivi per cui le alternative sono generalmente più sicure.
Bakuriu,

@Bakuriu - inoltre, se vuoi solo produrre un file pieno di zero (o piuttosto non ti importa di cosa ci sia dentro) usa troncato. È molto più veloce
Konrad Gajewski,

@KonradGajewski FYI truncate tenta di creare un file sparse (se questo è importante)
Xen2050

5
@Bakuriu headnon può svolgere questa attività senza l' -copzione non presente in POSIX . Non conosco nessuna versione catche possa risolvere questo problema. rsyncè un'utilità completamente non standard. Questo non è né qui né lì; sfogliando la sua pagina man, non vedo nemmeno come possa risolvere questo problema.
Kaz,

Tecnicamente, /dev/urandomnon è nemmeno in POSIX ...
Grawity il

Risposte:


92

bs, la dimensione del buffer, indica la dimensione di una singola chiamata read () eseguita da dd.

(Ad esempio, entrambi bs=1M count=1e bs=1k count=1ksi tradurrà in un file 1 MiB, ma la prima versione lo farà in un solo passaggio, mentre la seconda lo farà in 1024 piccoli blocchi.)

I file regolari possono essere letti a quasi tutte le dimensioni del buffer (purché il buffer si adatti alla RAM), ma i dispositivi e i file "virtuali" spesso lavorano molto vicino alle singole chiamate e hanno una restrizione arbitraria di quanti dati produrranno per read () call.

Per /dev/urandom, questo limite è definito in urandom_read () in 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));
    ...
}

Ciò significa che ogni volta che viene chiamata la funzione, bloccherà la dimensione richiesta a 33554431 byte.

Per impostazione predefinita, a differenza della maggior parte degli altri strumenti, dd non riproverà dopo aver ricevuto meno dati di quelli richiesti: ottieni 32 MiB e basta. (Per riprovare automaticamente, come nella risposta di Kamil, dovrai specificare iflag=fullblock.)


Si noti inoltre che "la dimensione di un singolo read ()" significa che l'intero buffer deve adattarsi alla memoria in una sola volta, quindi le dimensioni massime dei blocchi corrispondono anche all'utilizzo massiccio della memoria da parte di dd .

Ed è tutto inutile perché di solito non otterrai alcuna prestazione quando vai sopra ~ 16–32 blocchi MiB - le syscalls non sono la parte lenta qui, il generatore di numeri casuali lo è.

Quindi, per semplicità, basta usare head -c 1G /dev/urandom > output.


7
"... di solito non otterrai alcuna prestazione andando oltre ~ 16–32 blocchi MiB" - Nella mia esperienza, tendi a non guadagnare molto, o addirittura a perdere prestazioni superiori a 64-128 kilo byte. A quel punto, ti trovi bene nei rendimenti decrescenti rispetto al costo di syscall e la contesa della cache inizia a svolgere un ruolo.
marcelm,

3
@marcelm Ho aiutato a progettare sistemi ad alte prestazioni in cui le prestazioni di IO migliorerebbero con l'aumentare della dimensione dei blocchi a 1-2 MB e in alcuni casi fino a 8 MB circa. Per LUN. E poiché i filesystem sono stati costruiti utilizzando più LUN parallele, per ottenere le migliori prestazioni significava utilizzare più thread per IO, ciascuno con 1 MB + blocchi. Le frequenze di IO sostenute sono state di oltre 1 GB / sec. E quelli erano tutti dischi rotanti, quindi posso vedere array ad alte prestazioni di SSD che deglutiscono o generano dati sempre più velocemente man mano che la dimensione del blocco aumenta a 16 o addirittura 32 MB. Facilmente. Forse anche più grande.
Andrew Henle,

4
Noterò esplicitamente che si iflag=fullblocktratta di un'estensione GNU per l' ddutilità POSIX . Poiché la domanda non specifica Linux, penso che l'uso delle estensioni specifiche di Linux debba probabilmente essere esplicitamente notato per non confondere qualche futuro lettore che cerca di risolvere un problema simile su un sistema non Linux.
Andrew Henle,

6
@AndrewHenle Ah, interessante! Ho fatto un test veloce con ddsulla mia macchina, con blocchi di dimensioni da 1k a 512M. Leggendo da un SSD Intel 750, sono state ottenute prestazioni ottimali (circa 1300 MiB / s) a blocchi da 2 MiB, corrispondenti approssimativamente ai risultati. I blocchi di dimensioni maggiori non hanno aiutato né ostacolato. Leggendo da /dev/zero, le prestazioni ottimali (quasi 20GiB / s) erano a blocchi di 64 KiB e 128 KiB; sia i blocchi più piccoli che quelli più grandi hanno ridotto le prestazioni, adattandosi all'incirca al mio commento precedente. Bottom line: benchmark per la tua situazione attuale. E, naturalmente, nessuno di noi ha fatto un benchmark /dev/random: P
marcelm,

3
@ Xen2050 Ho fatto alcuni test più rapidi e sembra ddpiù veloce. Una rapida sequenza ha mostrato che headutilizza letture da 8 KiB e due scritture da 4KiB, il che è interessante (coreutils GNU 8.26 su Debian 9.6 / Linux 4.8). headle velocità sono davvero da qualche parte tra dd bs=4ke dd bs=8k. headle velocità sono inferiori del ~ 40% rispetto dd if=/dev/zero bs=64ke del ~ 25% rispetto a dd if=/dev/nvme0n1 bs=2M. Le letture /dev/zerosono ovviamente più limitate dalla CPU, ma anche per l'accodamento degli I / O SSD gioca un ruolo. È una differenza più grande di quanto mi aspettassi.
marzo

21

ddpuò leggere meno di ibs(nota: bsspecifica entrambi ibse obs), a meno che non iflag=fullblocksia specificato. 0+1 records inindica che 0sono 1stati letti blocchi completi e blocchi parziali. Tuttavia, qualsiasi blocco completo o parziale aumenta il contatore.

Non conosco il meccanismo esatto che fa ddleggere un blocco che è inferiore rispetto 1Ga questo caso particolare. Immagino che qualsiasi blocco venga letto nella memoria prima che sia scritto, quindi la gestione della memoria potrebbe interferire (ma questa è solo una supposizione). Modifica: questa risposta simultanea spiega il meccanismo che rende la ddlettura di un blocco inferiore rispetto 1Ga questo caso particolare.

Comunque, non lo consiglio così grande bs. Vorrei usare bs=1M count=1024. La cosa più importante è: senza iflag=fullblock alcun tentativo di lettura può leggere meno di ibs(a meno che ibs=1, a mio avviso, non sia abbastanza inefficiente).

Quindi, se hai bisogno di leggere una quantità esatta di dati, usa iflag=fullblock. Nota iflagnon è richiesta da POSIX, il tuo ddpotrebbe non supportarlo. Secondo questa risposta ibs=1 è probabilmente l'unico modo POSIX per leggere un numero esatto di byte. Naturalmente, se cambi ibs, dovrai ricalcolare il file count. Nel tuo caso l'abbassamento ibsa 32Mo meno probabilmente risolvere il problema, anche senza iflag=fullblock.

Nel mio Kubuntu avrei corretto il tuo comando in questo modo:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.