dd produit un fichier aléatoire de 32 Mo au lieu de 1 Go

50

Je voulais produire un fichier aléatoire de 1 Go, alors j'ai utilisé la commande suivante.

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

Mais chaque fois que je lance cette commande, je reçois un fichier de 32 Mo:

<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

Qu'est-ce qui ne va pas?

MODIFIER:

Merci à de bonnes réponses dans ce sujet, je suis venu avec une solution qui lit 32 morceaux de 32 Mo de large qui fait 1 Go:

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

Une autre solution a été donnée qui lit 1 Go directement dans la mémoire, puis écrit sur le disque. Cette solution nécessite beaucoup de mémoire, elle n’est donc pas recommandée:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock
Trismégistos
la source
3
IMHO Je ne pense pas qu'il y ait beaucoup de cas d'utilisation valables dd. Je utiliserais head, catou rsyncà sa place presque toujours. Et votre question si l’une des raisons pour lesquelles les alternatives sont généralement plus sûres.
Bakuriu
@ Bakuriu - aussi, si vous voulez juste produire un fichier plein de zéros (ou plutôt vous ne vous souciez pas de ce qui est dedans), utilisez tronqué. C'est beaucoup plus rapide.
Konrad Gajewski
@KonradGajewski FYI truncate tente de créer un fichier
fragmenté
5
@Bakuriu headne peut pas effectuer cette tâche sans l' -coption qui n'est pas dans POSIX . Je ne connais aucune version catqui puisse résoudre ce problème. rsyncest un utilitaire complètement non standard. Ce n'est ni ici ni là; En parcourant sa page de manuel, je ne vois pas non plus comment résoudre ce problème.
Kaz
Techniquement, ce /dev/urandomn'est pas non plus dans POSIX ...
grawity

Réponses:

92

bs, la taille du tampon, signifie la taille d’un seul appel read () effectué par dd.

(Par exemple, à la fois bs=1M count=1et bs=1k count=1kse traduira par un 1 fichier MiB, mais la première version fera en une seule étape, alors que le second fera en 1024 petits morceaux.)

Les fichiers normaux peuvent être lus à presque toutes les tailles de mémoire tampon (à condition que la mémoire tampon puisse tenir dans la RAM), mais les périphériques et les fichiers "virtuels" fonctionnent souvent très près des appels individuels et ont une restriction arbitraire quant à la quantité de données qu’ils produiront. read () appelle.

Pour /dev/urandom, cette limite est définie dans urandom_read () dans 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));
    ...
}

Cela signifie que chaque fois que la fonction est appelée, elle serre la taille demandée à 33554431 octets.

Par défaut, contrairement à la plupart des autres outils, dd ne réessayera pas après avoir reçu moins de données que demandé - vous obtenez le 32 Mo et c'est tout. (Pour le faire réessayer automatiquement, comme dans la réponse de Kamil, vous devrez spécifier iflag=fullblock.)


Notez également que "la taille d'un seul read ()" signifie que l'intégralité de la mémoire tampon doit tenir simultanément dans la mémoire. Par conséquent, les tailles de bloc massives correspondent également à l'utilisation massive de la mémoire par dd .

Et tout cela est inutile, car vous n'obtiendrez généralement aucune performance lorsque vous dépassez environ 16 à 32 blocs MiB - les appels système ne sont pas la partie la plus lente ici, mais le générateur de nombres aléatoires.

Donc, pour plus de simplicité, utilisez simplement head -c 1G /dev/urandom > output.

Grawity
la source
7
"... vous n'obtiendrez généralement pas de performances lorsque vous dépassez les blocs ~ 16–32 MIB" - D'après mon expérience, vous avez tendance à ne pas gagner beaucoup, voire à perdre de la performance au-dessus de 64-128 kilo octets. À ce stade, vous êtes bien dans les rendements décroissants par rapport au coût d'appel système, et les conflits de cache commencent à jouer un rôle.
Marcel
3
@marcelm J'ai aidé des architectes à créer des systèmes à hautes performances, où les performances des E / S seraient améliorées lorsque la taille des blocs passait à 1 ou 2 Mo, et dans certains cas jusqu'à 8 Mo environ. Par LUN. Et comme les systèmes de fichiers étaient construits en utilisant plusieurs LUN parallèles, pour obtenir les meilleures performances, il fallait utiliser plusieurs threads pour IO, chacun faisant plus de 1 Mo de blocs. Les taux d'entrées-sorties soutenus étaient supérieurs à 1 Go / s. Et c'étaient tous des disques en rotation, de sorte que je peux voir les matrices hautes performances de SSD avalant ou générant des données de plus en plus vite à mesure que la taille de bloc passe à 16, voire 32 blocs. Facilement. Peut-être même plus grand.
Andrew Henle
4
Je noterai explicitement qu'il iflag=fullblocks'agit d'une extension GNU de l' ddutilitaire POSIX . Comme la question ne spécifie pas Linux, je pense que l’utilisation d’extensions spécifiques à Linux devrait probablement être explicitement mentionnée, de manière à ne pas confondre les lecteurs futurs essayant de résoudre un problème similaire sur un système autre que Linux.
Andrew Henle
6
@ AndrewHenle Ah, intéressant! J'ai fait un test rapide avec ddsur ma machine, avec des tailles de blocs de 1k à 512M. En lisant sur un SSD Intel 750, des performances optimales (environ 1 300 Mo / s) ont été atteintes avec des blocs de 2 Mo, ce qui correspond approximativement à vos résultats. De plus grandes tailles de bloc n'a pas aidé ni empêché. La lecture de /dev/zero, performance optimale (près de 20 Go / s) était à 64 Ko et 128 Ko blocs; des blocs plus petits et plus grands ont diminué les performances, ce qui correspond approximativement à mon commentaire précédent. En bout de ligne: référence pour votre situation actuelle. Et bien sûr, aucun de nous n'a comparé /dev/random: P
marcelm
3
@ Xen2050 J'ai fait quelques tests plus rapides, et il semble que ce ddsoit plus rapide. Un résumé rapide a montré que l’ headutilisation de lectures de 8 Ko et de deux écritures de 4 Ko était intéressante (GNU coreutils 8.26 sur Debian 9.6 / Linux 4.8). headles vitesses sont en effet quelque part entre dd bs=4ket dd bs=8k. headles vitesses sont en baisse ~ 40% par rapport à dd if=/dev/zero bs=64ket en baisse ~ 25% par rapport à dd if=/dev/nvme0n1 bs=2M. Les lectures de /dev/zerosont bien sûr plus limitées en ressources CPU, mais pour le SSD I / O, la lecture joue également un rôle. C'est une différence plus grande que ce à quoi je m'attendais.
Marcel
21

ddpeut lire moins que ibs(note: bsspécifie les deux ibset obs), à moins que ne iflag=fullblocksoit spécifié. 0+1 records inindique que 0des blocs complets et 1un bloc partiel ont été lus. Cependant, tout blocage total ou partiel augmente le compteur.

Je ne connais pas le mécanisme exact qui permet de ddlire un bloc moins important que 1Gdans ce cas particulier. J'imagine que tout bloc est lu dans la mémoire avant son écriture, la gestion de la mémoire peut donc interférer (mais ce n'est qu'une supposition). Edit: cette réponse simultanée explique le mécanisme qui permet de ddlire un bloc qui est inférieur 1Gà ce qui est dans ce cas particulier

Quoi qu'il en soit, je ne recommande pas une telle taille bs. Je voudrais utiliser bs=1M count=1024. La chose la plus importante est: sans iflag=fullblock aucune tentative de lecture peut lire moins ibs( à moins que ibs=1, je pense, cela est tout à fait inefficace si).

Donc, si vous avez besoin de lire une quantité exacte de données, utilisez iflag=fullblock. Note iflagn’est pas requis par POSIX, vous ddne pouvez pas le supporter. Selon cette réponse, ibs=1 c'est probablement le seul moyen POSIX de lire un nombre exact d'octets. Bien sûr, si vous changez, ibsvous devrez recalculer le count. Dans votre cas, baisser ibsà 32Mou moins résoudra probablement le problème, même sans iflag=fullblock.

Dans mon Kubuntu, je corrigerais votre commande comme ceci:

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