2011-05-28 14 views
81

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

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

Estoy a punto de dd dos HDD Hitachi idénticos de 500 gb que funcionan a 7200rpm en una caja con un procesador Intel Core i3 con 4GB DDR3 1333mhz RAM, 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í.)

Respuesta

71

El tamaño de bloque óptimo depende de varios factores, incluido el sistema operativo (y su versión) y los diversos componentes de hardware autobuses y discos involucrados. Varios sistemas de tipo Unix (incluyendo Linux y al menos algunos de los sabores de BSD) definen el miembro st_blksize en el struct stat que da lo que piense el núcleo es el tamaño de bloque óptima:

#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 a experimentar: copia un gigabyte con varios tamaños de bloque y tiempo que. (Recuerde borrar los cachés de memoria intermedia del kernel antes de cada ejecución: echo 3 > /proc/sys/vm/drop_caches).

Sin embargo, como regla general, he encontrado que un tamaño de bloque lo suficientemente grande permite dd hacer un buen trabajo, y las diferencias entre, digamos, 64 KiB y 1 MiB son menores, en comparación con 4 KiB versus 64 KiB. (Aunque, claro, ha pasado un tiempo desde que lo hice. Ahora uso un mebibyte de forma predeterminada, o simplemente deje que dd elija el tamaño.)

+7

Lo siento por no haber aceptado nunca esta como la respuesta ... ¡gracias! – eckza

+0

Excelente punto acerca de recordar dejar cachés. ¡Esto estaba estropeando 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

3

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

+3

muchas versiones dd aceptan shorthands: ie 'bs = 8M' en GNU/Linux o' bs = 8m' en BSD – pascal

+1

lol, pensaste que ibas a decir "Prueba a partir de' bs = 8388608' y decrementa una vez cada paso " – lindhe

4

Puede intentar usar dd-opt, una pequeña utilidad que escribí.

(Mejoras/refinamientos son bienvenidos!)

+1

Woah - Y está escrito en Ruby? Bien! Definitivamente voy a estar dando esto un giro ! – eckza

+11

Actualmente (2012-08-09), dd-opt aún no funciona en sistemas operativos además de Mac OS X. – Henno

0
  • para una mejor performace utilizar el mayor tamaño de bloque que la RAM puede acomodar (enviará menos de I/O llama al sistema operativo)
  • para una mejor Precisión de y conjunto de recuperación de datos el tamaño de bloque para el tamaño de sector nativo de la entrada

Como los datos copias dd con el conv = noerror, opción de sincronización, los errores que encuentra resultará en el resto del bloque que está siendo reemplazado con cero bytes. Los tamaños de bloque más grandes se copiarán más rápidamente, pero cada vez que se encuentra un error, el resto del bloque se ignora.

source

6

he encontrado mi tamaño de bloque óptimo para ser de 8 MB que necesitaba para limpiar (algunos dicen: lavado) (igual a la caché de disco?) El espacio vacío en un disco antes de crear una imagen comprimida de eso I utilizados:

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

Experimenté con valores de 4K a 100M.

Después de dejar dd para funcionar durante un tiempo lo maté (Ctlr + C) y leer la salida:

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

como pantallas dd la velocidad de entrada/salida (19.1MB/s en este caso) que es fácil de ver si el valor que ha elegido tiene un mejor rendimiento 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 
+1

¿Solo ejecutó cada prueba una vez? Creo que lo que podría ver desde ≥64K es que el buffer es ya está lleno y la diferencia es solo la varianza aleatoria. –

+0

He escuchado una vez que los valores grandes potencialmente bloquean el sistema. La persona estaba trabajando con un archivo grande. Sería bueno si pudiera escuchar más sobre esto. –

+0

Mi experiencia también sugiere que '8M' es difícil de superar. –

44

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

Una cosa que es bastante confiable en 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 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 una historia bastante sólida de rendimiento fiable: 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/[email protected]/msg12073.html

Para determinar el tamaño de bloque de salida óptimo, He escrito el siguiente script que prueba escribir un archivo de prueba de 128M con dd en un rango de diferentes tamaños de bloques, desde el predeterminado de 512 bytes hasta un máximo de 64M. Ten en cuenta que este script usa dd internamente, así que úsalo 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 

View on GitHub

sólo lo he probado esta secuencia de comandos en un sistema Debian (Ubuntu) y en OSX Yosemite, por lo que probablemente tendrá algunos ajustes para hacer el trabajo en otros sabores de Unix.

De manera predeterminada, el comando creará un archivo de prueba llamado dd_obs_testfile en el directorio actual. Alternativamente, se puede proporcionar una ruta a un archivo de prueba personalizada, proporcionando un recorrido 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 respectivos transferencia tasas, 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 OS)

Para probar tamaño óptimo bloque de lectura, se puede usar más o menos el mismo proceso, pero en lugar de leer desde/dev/cero y writi En el disco, leería desde el el disco y escribiría en/dev/null. Una secuencia de comandos para hacer esto podría ser 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 

View on GitHub

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

Para mi hardware particular encontré que 128K era el tamaño de bloque de entrada más óptimo en una HDD y 32K era más óptimo en una SSD.

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

+0

He ejecutado el segundo script, que prueba el rendimiento de lectura, en un rMBP 2015 con 512G SSD. El mejor tamaño de bloque fue 8388608: 3.582 GB bytes/seg. –

+0

CORRECCIÓN: He ejecutado el segundo script, que prueba 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). (Clasifiqué los resultados incorrectamente al generar valores para mi último comentario.) –

+0

Para 'dd_obs_test.sh'' conv = fsync' no funciona en macOS y se puede eliminar. – rynop

Cuestiones relacionadas