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

122

Wie berechnet man die optimale Blockgröße beim Ausführen von a dd? Ich habe ein bisschen recherchiert und nichts gefunden, was darauf hindeutet, wie dies erreicht werden könnte.

Ich habe den Eindruck, dass eine größere Blockgröße zu einer schnelleren führen würde dd... ist das wahr?

Ich bin im Begriff, ddzwei identische 500-GB-Hitachi-Festplatten zu verwenden, die mit 7200 U / min auf einer Box mit einem Intel Core i3 mit 4 GB DDR3-RAM mit 1333 MHz laufen, also versuche ich herauszufinden, welche Blockgröße verwendet werden soll. (Ich werde Ubuntu 10.10 x86 von einem Flash-Laufwerk booten und von dort aus ausführen.)

eckza
quelle
Angenommene @ tdg5 Antwort für macOS - macos_dd_ibs_test.sh und macos_dd_obs_test.sh
mixel
1
Die beste Antwort wäre, eine Funktion beizutragen dd, um die optimale Blockgröße beim Übertragen der Datei zu finden
Boris
Warum wurde dieses Thema markiert und nicht zum Superuser migriert?
user267092

Antworten:

95

Die optimale Blockgröße hängt von verschiedenen Faktoren ab, einschließlich des Betriebssystems (und seiner Version) sowie der verschiedenen beteiligten Hardware-Busse und -Datenträger. Mehrere Unix-ähnliche Systeme (einschließlich Linux und zumindest einiger BSD-Varianten) definieren das st_blksizeMitglied in dem 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);
    }
}

Der beste Weg kann sein, zu experimentieren: Kopieren Sie ein Gigabyte mit verschiedenen Blockgrößen und Zeit, die. (Denken Sie daran, die Kernel-Puffer-Caches vor jedem Lauf zu löschen :) echo 3 > /proc/sys/vm/drop_caches.

Als Faustregel habe ich jedoch festgestellt, dass eine ausreichend große Blockgröße ddgute Arbeit leisten kann und die Unterschiede zwischen beispielsweise 64 KiB und 1 MiB im Vergleich zu 4 KiB gegenüber 64 KiB gering sind. (Allerdings ist es zugegebenermaßen eine Weile her, seit ich das getan habe. Ich verwende jetzt standardmäßig einen Mebibyte oder lasse einfach dddie Größe auswählen.)

Boiethios
quelle
11
Es tut mir so leid, dass ich das nie als Antwort akzeptiert habe ... danke!
Eckza
Hervorragender Punkt, um daran zu denken, Caches zu löschen. Das hat meine Messungen durcheinander gebracht! (Obwohl kleines Problem: Es ist "drop_caches", mit einem Unterstrich. Anscheinend müssen Änderungen mindestens 6 Zeichen sein ... :()
Tom
73

Wie andere gesagt haben, gibt es keine allgemein korrekte Blockgröße; Was für eine Situation oder eine Hardware optimal ist, kann für eine andere schrecklich ineffizient sein. Abhängig vom Zustand der Festplatten kann es auch vorzuziehen sein, eine andere Blockgröße als die "optimale" zu verwenden.

Eine Sache, die auf moderner Hardware ziemlich zuverlässig ist, ist, dass die Standardblockgröße von 512 Bytes fast eine Größenordnung langsamer ist als eine optimalere Alternative. Im Zweifelsfall habe ich festgestellt, dass 64K ein ziemlich solider moderner Standard ist. Obwohl 64K normalerweise nicht DIE optimale Blockgröße ist, ist es meiner Erfahrung nach viel effizienter als die Standardblockgröße. 64K hat auch eine ziemlich solide Geschichte der Zuverlässigkeit: Sie finden eine Nachricht aus der Eug-Lug-Mailingliste, circa 2002, in der eine Blockgröße von 64K empfohlen wird: http://www.mail-archive.com/eug- [email protected]/msg12073.html

Um die optimale Ausgabeblockgröße zu bestimmen, habe ich das folgende Skript geschrieben, das das Schreiben einer 128-MB-Testdatei mit dd in einem Bereich unterschiedlicher Blockgrößen testet, von standardmäßig 512 Byte bis maximal 64 MB. Seien Sie gewarnt, dieses Skript verwendet dd intern, verwenden Sie es daher mit 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

Ansicht auf GitHub

Ich habe dieses Skript nur auf einem Debian-System (Ubuntu) und unter OSX Yosemite getestet, daher sind wahrscheinlich einige Anpassungen erforderlich, um mit anderen Unix-Varianten arbeiten zu können.

Standardmäßig erstellt der Befehl eine Testdatei mit dem Namen dd_obs_testfile im aktuellen Verzeichnis. Alternativ können Sie einen Pfad zu einer benutzerdefinierten Testdatei angeben, indem Sie einen Pfad nach dem Skriptnamen 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 wie folgt:

$ ./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 Größe des Leseblocks 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 der Festplatte und schreiben in / dev / null. Ein Skript dafür könnte folgendermaßen 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

Ansicht auf GitHub

Ein wichtiger Unterschied in diesem Fall ist, dass die Testdatei eine Datei ist, 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 stellte ich fest, dass 128 KB die optimalste Eingangsblockgröße auf einer Festplatte und 32 KB die optimalste auf einer SSD waren.

Obwohl diese Antwort die meisten meiner Ergebnisse abdeckt, bin ich so oft auf diese Situation gestoßen, dass ich einen Blog-Beitrag darüber geschrieben habe: http://blog.tdg5.com/tuning-dd-block-size/ Weitere Einzelheiten finden Sie hier auf die Tests, die ich dort durchgeführt habe.

tdg5
quelle
1
Ich habe das zweite Skript zum Testen der Leseleistung auf einem 2015er rMBP mit 512G SSD ausgeführt. Die beste Blockgröße war 8388608: 3,582 GB Byte / Sek.
Quinn Comendant
1
KORREKTUR: Ich habe das zweite Skript zum Testen der Leseleistung auf einem 2015er rMBP mit 512 GB SSD ausgeführt. Die beste Blockgröße war 524288 (5,754 GB / s). Die zweitbeste Blockgröße betrug 131072 (5,133 GB / s). (Ich habe die Ergebnisse falsch sortiert, als ich Werte für meinen letzten Kommentar generiert habe.)
Quinn Comendant
For dd_obs_test.sh conv=fsyncfunktioniert nicht unter macOS und kann entfernt werden.
Rynop
Nach meiner Erfahrung erfordert das Benchmarking größerer Blockgrößen eine größere Stichprobe, um genau zu sein (einige Sekunden. Ich vermute, eine 128-MB-Datei sollte es schaffen, bin mir aber nicht sicher). Nicht sicher warum.
Rolf
2
Kumpel! Was für eine erstaunliche Antwort. Es ist, als würde man eine Goldmine finden, eine Tonne Schmutz ausgraben und dann verarbeiten, um das GOLD NUGGET zu finden, das ich wollte: 64K Vielen Dank.
SDsolar
10

Ich habe festgestellt, dass meine optimale Blockgröße 8 MB beträgt (entspricht dem Festplatten-Cache?). Ich musste den leeren Speicherplatz auf einer Festplatte löschen (einige sagen: waschen), bevor ich ein komprimiertes Image davon erstellen konnte. Ich benutzte:

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

Ich habe mit Werten von 4K bis 100M experimentiert.

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 Eingabe- / Ausgaberate anzeigt (in diesem Fall 19,1 MB / s), ist es leicht zu erkennen, ob der von Ihnen ausgewählte Wert besser oder schlechter als der vorherige 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   

Hinweis: Um zu überprüfen, wie groß Ihr Festplatten-Cache / Puffer ist, können Sie verwenden sudo hdparm -i /dev/sda

unfa
quelle
4
Haben Sie jeden Test nur einmal ausgeführt? Ich denke, was Sie von ≥64K sehen könnten, ist, dass der Puffer bereits voll ist und der Unterschied nur eine zufällige Varianz ist.
Mads Y
Ich habe einmal von großen Werten gehört, die möglicherweise zu einem Engpass im System führen. Die Person arbeitete mit einer großen Datei. Es wäre schön, wenn ich mehr darüber hören könnte.
Todd Partridge
1
Auch meine Erfahrung zeigt, dass 8Mes schwer zu schlagen ist.
Sridhar Sarnobat
Interessant. Denken Sie, dass dies mit der L3-Cache-Größe zusammenhängt oder nicht? Ich frage mich, ob Blockgrößen, die größer als der L3-Cache sind, langsamer werden würden.
SurpriseDog
3

Dies ist völlig systemabhängig. Sie sollten experimentieren, um die optimale Lösung zu finden. Versuchen Sie es mit bs=8388608. (Da Hitachi-Festplatten 8 MB Cache zu haben scheinen.)

ssapkota
quelle
5
Viele DD-Versionen akzeptieren Abkürzungen: dh bs=8Mauf GNU / Linux oder bs=8mauf BSD
Pascal
4
lol, dachte du würdest sagen "Versuche bs=8388608jeden Schritt einmal zu beginnen und zu dekrementieren"
lindhe
1
  • Verwenden Sie für eine bessere Leistung die größte Blockgröße, die Ihr RAM aufnehmen kann (sendet weniger E / A-Aufrufe an das Betriebssystem).
  • Stellen Sie für eine bessere Genauigkeit und Datenwiederherstellung die Blockgröße auf die native Sektorgröße der Eingabe ein

Wenn dd Daten mit der Option conv = noerror, sync kopiert, werden alle aufgetretenen Fehler dazu führen, dass der Rest des Blocks durch Null-Bytes ersetzt wird. Größere Blockgrößen werden schneller kopiert, aber jedes Mal, wenn ein Fehler auftritt, wird der Rest des Blocks ignoriert.

Quelle

eadmaster
quelle
1
Ich denke, wenn es irgendwelche Schreibfehler gibt, sollten Sie das Medium ersetzen, nicht die Blockgröße ändern ...
unfa