dd: ¿Cómo calcular el tamaño de bloque óptimo? [cerrado]

122

¿Cómo se calcula el tamaño de bloque óptimo cuando se ejecuta un dd? Lo he investigado un poco y no he encontrado nada que sugiera cómo se lograría.

Tengo la impresión de que un tamaño de bloque más grande daría como resultado una velocidad más rápida dd... ¿es esto cierto?

Estoy a punto de dddos discos duros Hitachi idénticos de 500 GB que funcionan a 7200 rpm en una caja que ejecuta un Intel Core i3 con 4 GB de RAM DDR3 de 1333 mhz, así que estoy tratando de averiguar qué tamaño de bloque usar. (Voy a iniciar Ubuntu 10.10 x86 desde una unidad flash y ejecutarlo desde allí).

eckza
fuente
Respuesta adoptada @ tdg5 para macOS - macos_dd_ibs_test.sh y macos_dd_obs_test.sh
mixel
1
la mejor respuesta sería contribuir con una función para ddencontrar el tamaño de bloque óptimo mientras se transfiere el archivo
Boris
¿Por qué se marcó este tema fuera de tema y no se migró a superusuario?
user267092

Respuestas:

95

El tamaño de bloque óptimo depende de varios factores, incluido el sistema operativo (y su versión) y los diversos buses de hardware y discos involucrados. Varios sistemas similares a Unix (incluido Linux y al menos algunos sabores de BSD) definen el st_blksizemiembro en el struct statque da lo que el kernel cree que es el tamaño de bloque óptimo:

#include <sys/stat.h>
#include <stdio.h>

int main(void)
{
    struct stat stats;

    if (!stat("/", &stats))
    {
        printf("%u\n", stats.st_blksize);
    }
}

La mejor manera puede ser experimentar: copiar un gigabyte con varios tamaños de bloque y tiempo. (Recuerde borrar los cachés del búfer del kernel antes de cada ejecución :) echo 3 > /proc/sys/vm/drop_caches.

Sin embargo, como regla general, he descubierto que un tamaño de bloque lo suficientemente grande permite ddhacer un buen trabajo, y las diferencias entre, digamos, 64 KiB y 1 MiB son menores, en comparación con 4 KiB frente a 64 KiB. (Aunque, es cierto, ha pasado un tiempo desde que hice eso. Ahora uso un mebibyte por defecto, o simplemente ddelijo el tamaño).

Boiethios
fuente
11
Siento mucho no haber aceptado esta como la respuesta ... ¡gracias!
eckza
Excelente punto sobre recordar soltar cachés. ¡Esto estaba arruinando mis medidas! (Aunque es un problema menor: es "drop_caches", con un guión bajo. Aparentemente, las ediciones deben tener al menos 6 caracteres ... :()
Tom
73

Como han dicho otros, no existe un tamaño de bloque universalmente correcto; lo que es óptimo para una situación o una pieza de hardware puede ser terriblemente ineficaz para otra. Además, dependiendo de la salud de los discos, puede ser preferible utilizar un tamaño de bloque diferente al "óptimo".

Una cosa que es bastante confiable en el hardware moderno es que el tamaño de bloque predeterminado de 512 bytes tiende a ser casi un orden de magnitud más lento que una alternativa más óptima. En caso de duda, descubrí que 64K es un valor predeterminado moderno bastante sólido. Aunque 64K generalmente no es EL tamaño de bloque óptimo, en mi experiencia tiende a ser mucho más eficiente que el predeterminado. 64K también tiene un historial bastante sólido de desempeño confiable: puede encontrar un mensaje de la lista de correo de Eug-Lug, alrededor de 2002, recomendando un tamaño de bloque de 64K aquí: http://www.mail-archive.com/eug- [email protected]/msg12073.html

Para determinar el tamaño óptimo del bloque de salida, escribí el siguiente script que prueba la escritura de un archivo de prueba de 128M con dd en un rango de diferentes tamaños de bloque, desde el valor predeterminado de 512 bytes hasta un máximo de 64M. Tenga en cuenta que este script utiliza dd internamente, así que utilícelo con precaución.

dd_obs_test.sh:

#!/bin/bash

# Since we're dealing with dd, abort if any errors occur
set -e

TEST_FILE=${1:-dd_obs_testfile}
TEST_FILE_EXISTS=0
if [ -e "$TEST_FILE" ]; then TEST_FILE_EXISTS=1; fi
TEST_FILE_SIZE=134217728

if [ $EUID -ne 0 ]; then
  echo "NOTE: Kernel cache will not be cleared between tests without sudo. This will likely cause inaccurate results." 1>&2
fi

# Header
PRINTF_FORMAT="%8s : %s\n"
printf "$PRINTF_FORMAT" 'block size' 'transfer rate'

# Block sizes of 512b 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M
for BLOCK_SIZE in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864
do
  # Calculate number of segments required to copy
  COUNT=$(($TEST_FILE_SIZE / $BLOCK_SIZE))

  if [ $COUNT -le 0 ]; then
    echo "Block size of $BLOCK_SIZE estimated to require $COUNT blocks, aborting further tests."
    break
  fi

  # Clear kernel cache to ensure more accurate test
  [ $EUID -eq 0 ] && [ -e /proc/sys/vm/drop_caches ] && echo 3 > /proc/sys/vm/drop_caches

  # Create a test file with the specified block size
  DD_RESULT=$(dd if=/dev/zero of=$TEST_FILE bs=$BLOCK_SIZE count=$COUNT conv=fsync 2>&1 1>/dev/null)

  # Extract the transfer rate from dd's STDERR output
  TRANSFER_RATE=$(echo $DD_RESULT | \grep --only-matching -E '[0-9.]+ ([MGk]?B|bytes)/s(ec)?')

  # Clean up the test file if we created one
  if [ $TEST_FILE_EXISTS -ne 0 ]; then rm $TEST_FILE; fi

  # Output the result
  printf "$PRINTF_FORMAT" "$BLOCK_SIZE" "$TRANSFER_RATE"
done

Ver en GitHub

Solo probé este script en un sistema Debian (Ubuntu) y en OSX Yosemite, por lo que probablemente necesitará algunos ajustes para que funcione en otros sabores de Unix.

Por defecto, el comando creará un archivo de prueba llamado dd_obs_testfile en el directorio actual. Alternativamente, puede proporcionar una ruta a un archivo de prueba personalizado proporcionando una ruta después del nombre del script:

$ ./dd_obs_test.sh /path/to/disk/test_file

La salida del script es una lista de los tamaños de bloque probados y sus respectivas tasas de transferencia, así:

$ ./dd_obs_test.sh
block size : transfer rate
       512 : 11.3 MB/s
      1024 : 22.1 MB/s
      2048 : 42.3 MB/s
      4096 : 75.2 MB/s
      8192 : 90.7 MB/s
     16384 : 101 MB/s
     32768 : 104 MB/s
     65536 : 108 MB/s
    131072 : 113 MB/s
    262144 : 112 MB/s
    524288 : 133 MB/s
   1048576 : 125 MB/s
   2097152 : 113 MB/s
   4194304 : 106 MB/s
   8388608 : 107 MB/s
  16777216 : 110 MB/s
  33554432 : 119 MB/s
  67108864 : 134 MB/s

(Nota: la unidad de las tasas de transferencia variará según el sistema operativo)

Para probar el tamaño de bloque de lectura óptimo, puede usar más o menos el mismo proceso, pero en lugar de leer desde / dev / zero y escribir en el disco, leería desde el disco y escribiría en / dev / null. Un script para hacer esto podría verse así:

dd_ibs_test.sh:

#!/bin/bash

# Since we're dealing with dd, abort if any errors occur
set -e

TEST_FILE=${1:-dd_ibs_testfile}
if [ -e "$TEST_FILE" ]; then TEST_FILE_EXISTS=$?; fi
TEST_FILE_SIZE=134217728

# Exit if file exists
if [ -e $TEST_FILE ]; then
  echo "Test file $TEST_FILE exists, aborting."
  exit 1
fi
TEST_FILE_EXISTS=1

if [ $EUID -ne 0 ]; then
  echo "NOTE: Kernel cache will not be cleared between tests without sudo. This will likely cause inaccurate results." 1>&2
fi

# Create test file
echo 'Generating test file...'
BLOCK_SIZE=65536
COUNT=$(($TEST_FILE_SIZE / $BLOCK_SIZE))
dd if=/dev/urandom of=$TEST_FILE bs=$BLOCK_SIZE count=$COUNT conv=fsync > /dev/null 2>&1

# Header
PRINTF_FORMAT="%8s : %s\n"
printf "$PRINTF_FORMAT" 'block size' 'transfer rate'

# Block sizes of 512b 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M
for BLOCK_SIZE in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864
do
  # Clear kernel cache to ensure more accurate test
  [ $EUID -eq 0 ] && [ -e /proc/sys/vm/drop_caches ] && echo 3 > /proc/sys/vm/drop_caches

  # Read test file out to /dev/null with specified block size
  DD_RESULT=$(dd if=$TEST_FILE of=/dev/null bs=$BLOCK_SIZE 2>&1 1>/dev/null)

  # Extract transfer rate
  TRANSFER_RATE=$(echo $DD_RESULT | \grep --only-matching -E '[0-9.]+ ([MGk]?B|bytes)/s(ec)?')

  printf "$PRINTF_FORMAT" "$BLOCK_SIZE" "$TRANSFER_RATE"
done

# Clean up the test file if we created one
if [ $TEST_FILE_EXISTS -ne 0 ]; then rm $TEST_FILE; fi

Ver en GitHub

Una diferencia importante en este caso es que el archivo de prueba es un archivo escrito por el script. ¡No apunte este comando a un archivo existente o el archivo existente se sobrescribirá con ceros!

Para mi hardware particular, descubrí que 128K era el tamaño de bloque de entrada más óptimo en un HDD y 32K era el más óptimo en un SSD.

Aunque esta respuesta cubre la mayoría de mis hallazgos, me he encontrado con esta situación suficientes veces que escribí una publicación de blog al respecto: http://blog.tdg5.com/tuning-dd-block-size/ Puede encontrar más detalles en las pruebas que realicé allí.

tdg5
fuente
1
Ejecuté el segundo script, probando el rendimiento de lectura, en un rMBP 2015 con 512G SSD. El mejor tamaño de bloque fue 8388608: 3,582 GB bytes / seg.
Quinn acusado
1
CORRECCIÓN: Ejecuté el segundo script, probando el rendimiento de lectura, en un rMBP 2015 con SSD de 512 GB. El mejor tamaño de bloque fue 524288 (5,754 GB / seg). El segundo mejor tamaño de bloque fue 131072 (5,133 GB / seg). (Ordené los resultados incorrectamente al generar valores para mi último comentario.)
Quinn Comendant
Porque dd_obs_test.sh conv=fsyncno funciona en macOS y se puede eliminar.
Rynop
En mi experiencia, la evaluación comparativa de tamaños de bloques más grandes necesita una muestra más grande para ser precisa (varios segundos. Supongo que debería ser un archivo de 128 MB, pero no estoy seguro). No estoy seguro de por qué.
Rolf
2
¡Tipo! Qué respuesta tan asombrosa. Es como encontrar una mina de oro, desenterrar una tonelada de tierra y luego procesarla para encontrar la pepita de oro que quería: 64K Muchas gracias.
SDsolar
10

Descubrí que mi tamaño de bloque óptimo es de 8 MB (¿igual al caché del disco?) Necesitaba limpiar (algunos dicen: lavar) el espacio vacío en un disco antes de crear una imagen comprimida del mismo. Solía:

cd /media/DiskToWash/
dd if=/dev/zero of=zero bs=8M; rm zero

Experimenté con valores de 4K a 100M.

Después de dejar que dd se ejecute por un tiempo, lo maté (Ctlr + C) y leí el resultado:

36+0 records in
36+0 records out
301989888 bytes (302 MB) copied, 15.8341 s, 19.1 MB/s

Como dd muestra la tasa de entrada / salida (19,1 MB / s en este caso), es fácil ver si el valor que ha elegido funciona mejor que el anterior o peor.

Mis puntuaciones:

bs=   I/O rate
---------------
4K    13.5 MB/s
64K   18.3 MB/s
8M    19.1 MB/s <--- winner!
10M   19.0 MB/s
20M   18.6 MB/s
100M  18.6 MB/s   

Nota: para comprobar cuál es el tamaño de la memoria caché / búfer de disco, puede utilizar sudo hdparm -i /dev/sda

unfa
fuente
4
¿Solo ejecutó cada prueba una vez? Creo que lo que puede ver en ≥64K es que el búfer ya está lleno y la diferencia es solo una variación aleatoria.
Mads Y
Una vez escuché hablar de grandes valores que potencialmente pueden obstaculizar el sistema. La persona estaba trabajando con un archivo grande. Sería bueno si pudiera escuchar más sobre esto.
Todd Partridge
1
Mi experiencia también sugiere que 8Mes difícil de superar.
Sridhar Sarnobat
Interesante. ¿Crees que esto se relaciona con el tamaño de la caché L3 o no? Me pregunto si los tamaños de bloque más grandes que el caché L3 irían más lentos.
SurpriseDog
3

Esto depende totalmente del sistema. Debe experimentar para encontrar la solución óptima. Intente comenzar con bs=8388608. (Como los HDD de Hitachi parecen tener una caché de 8 MB).

ssapkota
fuente
5
muchas versiones de dd aceptan abreviaturas: es decir, bs=8Men GNU / Linux o bs=8men BSD
pascal
4
lol, pensé que ibas a decir "Intenta comenzar bs=8388608y disminuir una vez en cada paso"
lindhe
1
  • Para un mejor rendimiento, utilice el tamaño de bloque más grande que pueda admitir la RAM (enviará menos llamadas de E / S al sistema operativo)
  • para una mejor precisión y recuperación de datos, configure el tamaño del bloque al tamaño del sector nativo de la entrada

Como dd copia datos con la opción conv = noerror, sync, cualquier error que encuentre resultará en que el resto del bloque sea reemplazado por bytes cero. Los tamaños de bloque más grandes se copiarán más rápidamente, pero cada vez que se encuentra un error, se ignora el resto del bloque.

fuente

eadmaster
fuente
1
Creo que si hay algún error de escritura deberá cambiar el medio, no cambia el tamaño de bloque ...
UNFA