dd: Jak obliczyć optymalny rozmiar bloku? [Zamknięte]

122

Jak obliczyć optymalny rozmiar bloku podczas uruchamiania dd? Trochę to zbadałem i nie znalazłem nic, co sugerowałoby, jak można to osiągnąć.

Mam wrażenie, że większy rozmiar bloku skutkowałby szybszym dd... czy to prawda?

Mam zamiar dddwa identyczne dyski twarde Hitachi 500 GB, które działają z prędkością 7200 obr./min na pudełku z procesorem Intel Core i3 z 4 GB pamięci RAM DDR3 1333 MHz, więc próbuję dowiedzieć się, jakiego rozmiaru bloków użyć. (Mam zamiar uruchomić Ubuntu 10.10 x86 z dysku flash i uruchomić go z tego).

eckza
źródło
Przyjęto odpowiedź @ tdg5 dla macOS - macos_dd_ibs_test.sh i macos_dd_obs_test.sh
mixel
1
najlepszą odpowiedzią byłoby dddodanie funkcji umożliwiającej znalezienie optymalnego rozmiaru bloku podczas przesyłania pliku
Boris
Dlaczego ten temat został oznaczony jako wyłączony z tematu i nie został przeniesiony do konta superużytkownika?
user267092,

Odpowiedzi:

95

Optymalny rozmiar bloku zależy od różnych czynników, w tym systemu operacyjnego (i jego wersji) oraz różnych magistral sprzętowych i dysków. Kilka systemów uniksopodobnych (w tym Linux i przynajmniej niektóre odmiany BSD) definiuje st_blksizeczłonka w tym, struct statktóry daje to, co jądro uważa za optymalny rozmiar bloku:

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

int main(void)
{
    struct stat stats;

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

Najlepszym sposobem może być eksperymentowanie: skopiuj gigabajt z różnymi rozmiarami bloków i czasem. (Pamiętaj, aby wyczyścić bufory jądra przed każdym uruchomieniem:) echo 3 > /proc/sys/vm/drop_caches.

Jednak z reguły stwierdziłem, że wystarczająco duży rozmiar bloku pozwala ddwykonać dobrą robotę, a różnice między, powiedzmy, 64 KiB i 1 MiB są niewielkie, w porównaniu do 4 KiB w porównaniu z 64 KiB. (Chociaż, co prawda, minęło trochę czasu, odkąd to zrobiłem. Domyślnie używam teraz mebibajta lub po prostu ddwybieram rozmiar).

Boiethios
źródło
11
Tak mi przykro, że nigdy nie zaakceptowałem tego jako odpowiedzi ... dzięki!
eckza
Doskonały punkt dotyczący pamiętania o upuszczaniu pamięci podręcznych. To zepsuło moje pomiary! (Chociaż drobny problem: to „drop_caches” z podkreśleniem. Najwyraźniej zmiany muszą mieć co najmniej 6 znaków ... :()
Tom
73

Jak powiedzieli inni, nie ma uniwersalnie poprawnego rozmiaru bloku; to, co jest optymalne dla jednej sytuacji lub jednego elementu sprzętu, może być strasznie nieefektywne dla innego. Ponadto, w zależności od kondycji dysków, może być lepsze użycie innego rozmiaru bloku niż „optymalny”.

Jedną z rzeczy, która jest dość niezawodna na nowoczesnym sprzęcie, jest to, że domyślny rozmiar bloku 512 bajtów jest prawie o rząd wielkości wolniejszy niż bardziej optymalna alternatywa. W razie wątpliwości stwierdziłem, że 64K to całkiem solidna, nowoczesna opcja domyślna. Chociaż 64K zwykle nie jest optymalnym rozmiarem bloku, z mojego doświadczenia wynika, że ​​jest o wiele bardziej wydajny niż domyślny. 64K ma również dość solidną historię niezawodnej wydajności: Możesz znaleźć wiadomość z listy mailingowej Eug-Lug z około 2002 roku, zalecającą rozmiar bloku 64K tutaj: http://www.mail-archive.com/eug- [email protected]/msg12073.html

Aby określić optymalny rozmiar bloku wyjściowego, napisałem następujący skrypt, który testuje zapisywanie pliku testowego 128 MB z dd w zakresie różnych rozmiarów bloków, od domyślnych 512 bajtów do maksymalnie 64 MB. Ostrzegamy, ten skrypt używa dd wewnętrznie, więc używaj go ostrożnie.

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

Zobacz na GitHub

Testowałem ten skrypt tylko w systemie Debian (Ubuntu) i na OSX Yosemite, więc prawdopodobnie zajmie to trochę poprawek, aby działać na innych odmianach Uniksa.

Domyślnie polecenie utworzy plik testowy o nazwie dd_obs_testfile w bieżącym katalogu. Alternatywnie możesz podać ścieżkę do niestandardowego pliku testowego, podając ścieżkę po nazwie skryptu:

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

Wynikiem skryptu jest lista testowanych rozmiarów bloków i odpowiadające im szybkości przesyłania, takie jak:

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

(Uwaga: jednostka szybkości przesyłania różni się w zależności od systemu operacyjnego)

Aby przetestować optymalny rozmiar bloku odczytu, możesz użyć mniej więcej tego samego procesu, ale zamiast czytać z / dev / zero i zapisywać na dysku, czytasz z dysku i zapisujesz do / dev / null. Skrypt, który to zrobi, może wyglądać następująco:

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

Zobacz na GitHub

Istotną różnicą w tym przypadku jest to, że plik testowy jest plikiem zapisywanym przez skrypt. Nie kieruj tego polecenia na istniejący plik lub istniejący plik zostanie nadpisany zerami!

W przypadku mojego konkretnego sprzętu stwierdziłem, że 128 KB było najbardziej optymalnym rozmiarem bloku wejściowego na dysku twardym, a 32 KB było najbardziej optymalne na dysku SSD.

Chociaż ta odpowiedź obejmuje większość moich ustaleń, napotkałem tę sytuację wystarczająco dużo razy, że napisałem o niej post na blogu: http://blog.tdg5.com/tuning-dd-block-size/ Możesz znaleźć więcej szczegółów na testach, które tam przeprowadziłem.

tdg5
źródło
1
Uruchomiłem drugi skrypt, testujący wydajność odczytu, na rMBP 2015 z dyskiem SSD 512G. Najlepszy rozmiar bloku to 8388608: 3,582 GB bajtów / s.
Quinn Comendant
1
POPRAWKA: Uruchomiłem drugi skrypt, testujący wydajność odczytu, na rMBP 2015 z dyskiem SSD 512 GB. Najlepszy rozmiar bloku to 524288 (5,754 GB / s). Drugi najlepszy rozmiar bloku to 131072 (5,133 GB / s). (Niepoprawnie posortowałem wyniki podczas generowania wartości dla mojego ostatniego komentarza.)
Quinn Comendant
Dla dd_obs_test.sh conv=fsyncnie działa na MacOS i mogą być usunięte.
rynop
Z mojego doświadczenia wynika, że ​​testowanie większych rozmiarów bloków wymaga większej próbki, aby było dokładne (kilka sekund. Domyślam się, że plik 128 MB powinien to zrobić, ale nie jestem pewien). Nie pewny dlaczego.
Rolf
2
Koleś! Cóż za niesamowita odpowiedź. To tak, jakby znaleźć kopalnię złota, wykopać tonę ziemi, a następnie przetworzyć ją, aby znaleźć ZŁOTY NUGGET, którego szukałem: 64K Dziękuję bardzo.
SDsolar
11

Okazało się, że mój optymalny rozmiar bloku to 8 MB (równy pamięci podręcznej dysku?). Musiałem wyczyścić (niektórzy mówią: umyć) puste miejsce na dysku przed utworzeniem jego skompresowanego obrazu. Użyłem:

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

Eksperymentowałem z wartościami od 4K do 100M.

Po dłuższym uruchomieniu dd zabiłem go (Ctlr + C) i przeczytałem wyjście:

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

Ponieważ dd wyświetla szybkość wejścia / wyjścia (w tym przypadku 19,1 MB / s), łatwo jest sprawdzić, czy wybrana wartość działa lepiej niż poprzednia, czy gorzej.

Moje wyniki:

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   

Uwaga: Aby sprawdzić, jaki jest rozmiar pamięci podręcznej / bufora dysku, możesz użyć sudo hdparm -i /dev/sda

unfa
źródło
4
Czy wykonałeś każdy test tylko raz? Myślę, że to, co możesz zobaczyć z ≥64K, to to, że bufor jest już pełny, a różnica jest po prostu przypadkową wariancją.
Mads Y
Słyszałem kiedyś o dużych wartościach, które mogą utrudniać system. Osoba pracowała z dużym plikiem. Byłoby miło, gdybym mógł więcej o tym usłyszeć.
Todd Partridge,
1
Moje doświadczenie również sugeruje, że 8Mjest trudny do pokonania.
Sridhar Sarnobat
Ciekawy. Myślisz, że odnosi się to do rozmiaru pamięci podręcznej L3, czy nie? Zastanawiam się, czy rozmiary bloków większe niż pamięć podręczna L3 byłyby wolniejsze.
SurpriseDog
3

Jest to całkowicie zależne od systemu. Należy poeksperymentować, aby znaleźć optymalne rozwiązanie. Spróbuj zacząć od bs=8388608. (Ponieważ dyski twarde Hitachi wydają się mieć 8 MB pamięci podręcznej).

ssapkota
źródło
5
wiele wersji dd akceptuje skróty: tj. bs=8Mna GNU / Linuksie lub bs=8mna BSD
pascal
4
lol, pomyślałem, że powiesz „Spróbuj zacząć od bs=8388608i zmniejszaj raz na każdy krok”
lindhe
1
  • aby uzyskać lepszą wydajność, użyj największego rozmiaru bloków, jaki może pomieścić pamięć RAM (wyśle ​​mniej wywołań we / wy do systemu operacyjnego)
  • aby uzyskać lepszą dokładność i odzyskiwanie danych, ustaw rozmiar bloku na rodzimy rozmiar sektora wejścia

Ponieważ dd kopiuje dane z opcją conv = noerror, sync, wszelkie napotkane błędy spowodują, że pozostała część bloku zostanie zastąpiona bajtami zerowymi. Większe bloki będą kopiowane szybciej, ale za każdym razem, gdy napotkany zostanie błąd, reszta bloku jest ignorowana.

źródło

eadmaster
źródło
1
Myślę, że jeśli są jakieś błędy zapisu to należy wymienić nośnik, nie zmieniać rozmiaru bloku ...
unfa