dd está produciendo un archivo aleatorio de 32 MB en lugar de 1 GB

50

Quería producir un archivo aleatorio de 1 GB, así que utilicé el siguiente comando.

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

Pero cada vez que ejecuto este comando obtengo un archivo 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

¿Qué está mal?

EDITAR:

Gracias a las excelentes respuestas en este tema, llegué con una solución que lee 32 fragmentos de 32 MB de tamaño, lo que hace que 1 GB:

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

Se dio otra solución que lee 1 GB directamente en la memoria y luego escribe en el disco. Esta solución toma mucha memoria, por lo que no se prefiere:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock
Trismegistos
fuente
3
En mi humilde opinión, no creo que haya muchos casos de uso válidos dden absoluto. Yo usaría head, cato rsyncen su lugar casi siempre. Y su pregunta es una de las razones por las cuales las alternativas son generalmente más seguras.
Bakuriu
@Bakuriu: también, si solo desea producir un archivo lleno de ceros (o más bien no le importa lo que hay dentro), use truncar. Es mucho mas rapido.
Konrad Gajewski
@KonradGajewski FYI truncado intenta hacer un archivo escaso (si eso importa)
Xen2050
55
@Bakuriu headno puede hacer esta tarea sin la -copción que no está en POSIX . No conozco ninguna versión catque pueda resolver esto. rsyncEs una utilidad completamente no estándar. Eso no está ni aquí ni allá; hojeando su página de manual, tampoco veo cómo puede resolver este problema.
Kaz
Técnicamente, /dev/urandomtampoco está en POSIX ...
grawity

Respuestas:

92

bs, el tamaño del búfer, significa el tamaño de una sola llamada read () realizada por dd.

(Por ejemplo, tanto bs=1M count=1y bs=1k count=1kresultará en un archivo de 1 MiB, pero la primera versión lo hará en un solo paso, mientras que la segunda lo hará en 1024 trozos pequeños.)

Los archivos normales se pueden leer en casi cualquier tamaño de búfer (siempre que el búfer se ajuste a la RAM), pero los dispositivos y los archivos "virtuales" a menudo funcionan muy cerca de las llamadas individuales y tienen una restricción arbitraria de la cantidad de datos que producirán por llamada read ().

Para /dev/urandom, este límite se define en urandom_read () en 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));
    ...
}

Esto significa que cada vez que se llama a la función, fijará el tamaño solicitado a 33554431 bytes.

De manera predeterminada, a diferencia de la mayoría de las otras herramientas, dd no volverá a intentarlo después de recibir menos datos de los solicitados: obtiene el 32 MiB y listo. (Para que vuelva a intentarlo automáticamente, como en la respuesta de Kamil, deberá especificar iflag=fullblock).


Tenga en cuenta también que "el tamaño de una sola lectura ()" significa que todo el búfer debe caber en la memoria a la vez, por lo que los tamaños de bloque masivos también corresponden al uso masivo de memoria por parte de dd .

Y todo es inútil porque generalmente no obtendrá ningún rendimiento cuando supere ~ 16–32 bloques MiB: las llamadas al sistema no son la parte lenta aquí, sino el generador de números aleatorios.

Entonces, por simplicidad, solo use head -c 1G /dev/urandom > output.

Gravedad
fuente
77
"... por lo general, no obtendrá ningún rendimiento cuando supere los ~ 16–32 bloques MiB" : en mi experiencia, tiende a no ganar mucho, o incluso a perder el rendimiento por encima de 64-128 kilobytes . En ese punto, está bien en los rendimientos decrecientes wrt syscall cost, y la contención de caché comienza a desempeñar un papel.
marcelm
3
@marcelm He ayudado a diseñar sistemas de alto rendimiento donde el rendimiento de E / S mejoraría a medida que el tamaño del bloque aumentara a bloques de 1-2 MB, y en algunos casos hasta 8 MB más o menos. Por LUN Y a medida que los sistemas de archivos se construyeron usando múltiples LUN paralelos, para obtener el mejor rendimiento significaba usar múltiples hilos para IO, cada uno con bloques de 1 MB +. Las tasas de IO sostenidas fueron superiores a 1 GB / seg. Y esos eran todos discos giratorios, por lo que puedo ver matrices de SSD de alto rendimiento que tragan o generan datos cada vez más rápido a medida que el tamaño del bloque crece a 16 o incluso 32 MB de bloques. Fácilmente. Quizás incluso más grande.
Andrew Henle
44
Notaré explícitamente que iflag=fullblockes una extensión de GNU para la ddutilidad POSIX . Como la pregunta no especifica Linux, creo que el uso de extensiones específicas de Linux probablemente debería notarse explícitamente para que algún futuro lector que intente resolver un problema similar en un sistema que no sea Linux se confunda.
Andrew Henle
66
@ AndrewHenle ¡Ah, interesante! Hice una prueba rápida con ddmi máquina, con tamaños de bloque de 1k a 512M. Leyendo de un SSD Intel 750, se logró un rendimiento óptimo (aproximadamente 1300MiB / s) en bloques de 2MiB, que coinciden aproximadamente con sus resultados. Los tamaños de bloque más grandes no ayudaron ni obstaculizaron. Leyendo /dev/zero, el rendimiento óptimo (casi 20GiB / s) estaba en bloques de 64KiB y 128KiB; tanto pequeños y grandes bloques disminución del rendimiento, coincidiendo más o menos mi comentario anterior. En pocas palabras: punto de referencia para su situación real. Y, por supuesto, ninguno de nosotros /dev/random
comparó
3
@ Xen2050 Hice algunas pruebas más rápidas, y parece que ddes más rápido. Una versión rápida mostró que headusa lecturas de 8KiB y dos escrituras de 4KiB, lo cual es interesante (GNU coreutils 8.26 en Debian 9.6 / Linux 4.8). headlas velocidades están en algún lugar entre dd bs=4ky dd bs=8k. headlas velocidades disminuyeron ~ 40% en comparación con dd if=/dev/zero bs=64ky disminuyeron ~ 25% en comparación con dd if=/dev/nvme0n1 bs=2M. Las lecturas de /dev/zero, por supuesto, están más limitadas por la CPU, pero para el SSD I / O queing también juega un papel. Es una diferencia más grande de lo que esperaba.
marcelm
21

ddpuede leer menos de ibs(nota: bsespecifica ambos ibsy obs), a menos que iflag=fullblockse especifique. 0+1 records inindica que se leyeron 0bloques completos y 1bloque parcial. Sin embargo, cualquier bloqueo total o parcial aumenta el contador.

No sé el mecanismo exacto que hace que ddleer un bloque sea menor que 1Gen este caso particular. Supongo que cualquier bloque se lee en la memoria antes de que se escriba, por lo que la gestión de la memoria puede interferir (pero esto es solo una suposición). Editar: esta respuesta concurrente explica el mecanismo que hace que ddleer un bloque sea menor que 1Gen este caso particular.

De todos modos, no recomiendo tan grande bs. Me gustaría utilizar bs=1M count=1024. Lo más importante es: sin iflag=fullblock ningún intento de lectura, puede leer menos de ibs(a menos ibs=1, creo, que esto es bastante ineficiente).

Entonces, si necesita leer una cantidad exacta de datos, úsela iflag=fullblock. Nota iflagno es requerida por POSIX, es ddposible que no la admita. Según esta respuesta, ibs=1 es probablemente la única forma POSIX de leer un número exacto de bytes. Por supuesto, si cambia ibs, deberá volver a calcular el count. En su caso la reducción ibsa 32Mo menos probable que se solucionará el problema, incluso sin iflag=fullblock.

En mi Kubuntu arreglaría tu comando así:

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