it-swarm.com.de

dd: Wie berechnet man die optimale Blockgröße?

Wie berechnen Sie die optimale Blockgröße, wenn Sie eine dd ausführen? Ich habe etwas recherchiert und nichts gefunden, was darauf schließen lässt.

Ich habe den Eindruck, dass eine größere Blockgröße zu einer schnelleren dd... führt. Stimmt das?

Ich bin dabei dd zwei identische 500-GB-Hitachi-Festplatten, die bei 7200 U/min auf einer Box laufen, auf der ein Intel Core i3 mit 4 GB DDR3 1333 MHz RAM läuft. (Ich werde Ubuntu 10.10 x86 von einem Flash-Laufwerk booten und von dort ausführen.)

95
eckza

Die optimale Blockgröße hängt von verschiedenen Faktoren ab, einschließlich des Betriebssystems (und seiner Version) und der verschiedenen beteiligten Hardwarebusse und Festplatten. Mehrere Unix-ähnliche Systeme (einschließlich Linux und zumindest einige BSD-Varianten) definieren das st_blksize-Member im struct stat, das angibt, was der Kernel für die optimale Blockgröße hält:

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

int main(void)
{
    struct stat stats;

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

Am besten experimentieren Sie vielleicht: Kopieren Sie ein Gigabyte mit verschiedenen Blockgrößen und Zeit. (Denken Sie daran, die Kernel-Puffercaches vor jedem Lauf zu löschen: echo 3 > /proc/sys/vm/drop_caches).

Als Faustregel habe ich jedoch herausgefunden, dass eine ausreichend große Blockgröße dd gute Arbeit leistet, und die Unterschiede zwischen beispielsweise 64 KiB und 1 MiB sind gering, verglichen mit 4 KiB gegenüber 64 KiB. (Allerdings ist es schon eine Weile her, seit ich das getan habe. Ich benutze jetzt standardmäßig einen Mebibyte oder lasse dd die Größe auswählen.)

79
user25148

Wie andere bereits gesagt haben, gibt es keine allgemein korrekte Blockgröße. Was für eine Situation oder ein Hardwareteil optimal ist, kann für eine andere furchtbar ineffizient sein. Abhängig vom Zustand der Platten kann es auch vorzuziehen sein, eine andere Blockgröße als "optimal" zu verwenden.

Eine Sache, die auf moderner Hardware ziemlich zuverlässig ist, ist, dass die Standardblockgröße von 512 Bytes in der Regel um eine Größenordnung langsamer ist als eine optimalere Alternative. Im Zweifel habe ich festgestellt, dass 64K ein ziemlich solider moderner Standard ist. Obwohl 64K normalerweise nicht die optimale Blockgröße ist, ist sie meiner Erfahrung nach viel effizienter als die Standardgröße. 64K hat auch eine ziemlich solide Geschichte, zuverlässig zu sein: Sie finden eine Nachricht aus der Eug-Lug-Mailingliste (ca. 2002), die eine Blockgröße von 64K empfiehlt: http://www.mail-archive.com/ [email protected]/msg12073.html

Um die optimale Ausgabeblockgröße zu ermitteln, habe ich das folgende Skript geschrieben, das das Schreiben einer 128-MB-Testdatei mit dd in einem Bereich verschiedener Blockgrößen testet, von 512 Byte bis zu maximal 64 MB. Seien Sie gewarnt, dieses Skript verwendet intern dd, verwenden Sie also Vorsicht.

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 auf GitHub

Ich habe dieses Skript nur auf einem Debian (Ubuntu) -System und auf OSX Yosemite getestet. Es wird also wahrscheinlich einige Optimierungsschritte erfordern, um andere Unix-Varianten nutzen zu können.

Der Befehl erstellt standardmäßig eine Testdatei mit dem Namen dd_obs_testfile im aktuellen Verzeichnis. Alternativ können Sie einen Pfad zu einer benutzerdefinierten Testdatei angeben, indem Sie nach dem Skriptnamen einen Pfad angeben:

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

Die Ausgabe des Skripts ist eine Liste der getesteten Blockgrößen und ihrer jeweiligen Übertragungsraten

$ ./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

(Hinweis: Die Einheit der Übertragungsraten variiert je nach Betriebssystem.)

Um die optimale Leseblockgröße zu testen, können Sie mehr oder weniger denselben Prozess verwenden, Statt jedoch aus/dev/zero zu lesen und auf die Festplatte zu schreiben, lesen Sie von Die Festplatte und schreiben in/dev /Null. Ein Skript dazu könnte so aussehen:

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 auf GitHub

Ein wichtiger Unterschied in diesem Fall ist, dass es sich bei der Testdatei um eine Datei handelt, die vom Skript geschrieben wird. Richten Sie diesen Befehl nicht auf eine vorhandene Datei, da sonst die vorhandene Datei mit Nullen überschrieben wird!

Für meine spezielle Hardware habe ich festgestellt, dass 128K die optimale Eingangsblockgröße auf einer Festplatte und 32K auf einer SSD am besten war.

Obwohl diese Antwort die meisten meiner Befunde abdeckt, bin ich oft genug in diese Situation geraten, dass ich darüber einen Blogbeitrag geschrieben habe: http://blog.tdg5.com/tuning-dd-block-size/ You finden Sie genauere Angaben zu den dort durchgeführten Tests.

58
tdg5

Ich habe festgestellt, dass meine optimale Blockgröße 8 MB beträgt (entspricht dem Festplattencache?). Ich musste den leeren Speicherplatz auf einer Festplatte löschen (einige sagen: "Waschen"), bevor ein komprimiertes Image davon erstellt wurde.

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

Ich experimentierte mit Werten von 4K bis 100M.

Nachdem ich dd eine Weile laufen ließ, tötete ich es (Ctlr + C) und las die Ausgabe:

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

Da dd die Eingangs-/Ausgangsrate (in diesem Fall 19,1 MB/s) anzeigt, können Sie leicht erkennen, ob der von Ihnen gewählte Wert besser als der vorherige oder schlechter ist.

Meine Ergebnisse:

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
7
unfa

Sie könnten versuchen, dd-opt zu verwenden, ein kleines Dienstprogramm, das ich geschrieben habe.

(Verbesserungen/Verbesserungen willkommen!)

4
sampablokuper

Dies ist völlig systemabhängig. Sie sollten versuchen, die optimale Lösung zu finden Versuchen Sie, mit bs=8388608 zu beginnen. (Da Hitachi-Festplatten scheinbar über 8 MB Cache verfügen.)

3
ssapkota
  • für eine bessere Performance verwenden Sie die größte Blockgröße, die Sie für RAM verwenden können (es werden weniger E/A-Aufrufe an das Betriebssystem gesendet).
  • für eine bessere Genauigkeit und Datenwiederherstellung setzen Sie die Blockgröße auf die native Sektorgröße der Eingabe

Da dd Daten mit der Option conv = noerror, sync kopiert, führen alle Fehler, die dabei auftreten, dazu, dass der Rest des Blocks durch null Byte ersetzt wird. Größere Blockgrößen werden schneller kopiert, aber jedes Mal, wenn ein Fehler auftritt, wird der Rest des Blocks ignoriert.

Quelle

0
eadmaster