dd tworzy losowy plik 32 MB zamiast 1 GB

50

Chciałem utworzyć losowy plik 1 GB, więc użyłem następującego polecenia.

dd if=/dev/urandom of=output bs=1G count=1

Zamiast tego za każdym razem, gdy uruchamiam to polecenie, otrzymuję plik 32 MB:

<11:58:40>$ dd if=/dev/urandom of=output bs=1G count=1
0+1 records in
0+1 records out
33554431 bytes (34 MB, 32 MiB) copied, 0,288321 s, 116 MB/s

Co jest nie tak?

EDYTOWAĆ:

Dzięki świetnym odpowiedziom w tym temacie doszedłem do rozwiązania, które odczytuje 32 fragmenty o wielkości 32 MB, co daje 1 GB:

dd if=/dev/urandom of=output bs=32M count=32

Podano inne rozwiązanie, które odczytuje 1 GB bezpośrednio do pamięci, a następnie zapisuje na dysku. To rozwiązanie zajmuje dużo pamięci, więc nie jest preferowane:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock
Trismegistos
źródło
3
IMHO Nie wydaje mi się, żeby w ogóle było wiele ważnych przypadków użycia dd. Używałbym head, catalbo rsyncprawie zawsze na swoim miejscu. I twoje pytanie, czy jeden z powodów, dla których alternatywy są zwykle bezpieczniejsze.
Bakuriu
@ Bakuriu - także, jeśli chcesz po prostu utworzyć plik pełen zer (lub raczej nie martwisz się o to, co jest w środku), użyj obcinania. Jest znacznie szybszy.
Konrad Gajewski
@KonradGajewski FYI obcinanie próbuje utworzyć rzadki plik (jeśli to ma znaczenie)
Xen2050,
5
@ Bakuriu headnie może wykonać tego zadania bez -copcji, która nie jest w POSIX . Nie znam żadnej wersji, catktóra mogłaby to rozwiązać. rsyncjest całkowicie niestandardowym narzędziem. Tego tu nie ma; przeglądając stronę podręcznika, nie widzę też, jak mógłby rozwiązać ten problem.
Kaz
Technicznie rzecz biorąc, /dev/urandomnie ma go również w POSIX ...
grawitacja

Odpowiedzi:

92

bs, rozmiar bufora, oznacza rozmiar pojedynczego wywołania read () wykonanego przez dd.

(Na przykład zarówno bs=1M count=1i bs=1k count=1kspowoduje powstanie pliku 1 MiB, ale pierwsza wersja zrobi to w jednym kroku, a druga zrobi to w 1024 małych porcjach.)

Zwykłe pliki mogą być odczytywane przy prawie dowolnym rozmiarze bufora (o ile bufor ten mieści się w pamięci RAM), ale urządzenia i pliki „wirtualne” często działają bardzo blisko poszczególnych wywołań i mają pewne arbitralne ograniczenie ilości danych, które będą wytwarzać na Wywołanie read ().

Za /dev/urandomgranica ta jest zdefiniowana w urandom_read () w drivers / char / random.c :

#define ENTROPY_SHIFT 3

static ssize_t
urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
    nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
    ...
}

Oznacza to, że za każdym razem, gdy wywoływana jest funkcja, żądany rozmiar zostanie ograniczony do 33554431 bajtów.

Domyślnie, w przeciwieństwie do większości innych narzędzi, dd nie będzie ponawiać próby po otrzymaniu mniejszej ilości danych niż zażądano - dostajesz 32 MiB i to wszystko. (Aby ponownie spróbować automatycznie, tak jak w odpowiedzi Kamila, musisz określić iflag=fullblock.)


Zauważ też, że „rozmiar pojedynczego odczytu ()” oznacza, że ​​cały bufor musi jednocześnie zmieścić się w pamięci, więc ogromne rozmiary bloków również odpowiadają ogromnemu zużyciu pamięci przez dd .

I to wszystko nie ma sensu, ponieważ zwykle nie osiągniesz żadnej wydajności, gdy przekroczysz ~ 16–32 bloków MiB - wywołania systemowe nie są tutaj wolną częścią, generator liczb losowych jest.

Więc dla uproszczenia, po prostu użyj head -c 1G /dev/urandom > output.

grawitacja
źródło
7
„... zazwyczaj nie zyska żadnych wyników, gdy dzieje powyżej ~ 16-32 MIB bloków” - Z mojego doświadczenia wynika, że nie wydają się uzyskać znacznie lub nawet utratę wydajności powyżej 64-128 kilo bajt. W tym momencie masz już dość malejących kosztów wrs syscall, a rywalizacja o pamięć podręczną zaczyna odgrywać pewną rolę.
marcelm
3
@marcelm Pomogłem w zaprojektowaniu systemów o wysokiej wydajności, w których wydajność IO poprawiłaby się wraz ze wzrostem wielkości bloku do 1-2 MB bloków, aw niektórych przypadkach nawet do 8 MB. Na jednostkę LUN. Ponieważ systemy plików zostały zbudowane przy użyciu wielu równoległych jednostek LUN, uzyskanie najlepszej wydajności oznaczało użycie wielu wątków dla operacji we / wy, z których każdy wykonuje bloki 1 MB +. Utrzymane stawki IO wynosiły ponad 1 GB / s. A wszystko to wirujące dyski, więc widzę szybsze macierze dysków SSD połykających lub generujących dane coraz szybciej, gdy rozmiar bloku rośnie do 16 lub nawet 32 ​​MB bloków. Z łatwością. Może nawet większy.
Andrew Henle
4
Wyraźnie zauważę, że iflag=fullblockjest to rozszerzenie GNU do narzędzia POSIXdd . Ponieważ pytanie nie określa Linuksa, myślę, że użycie rozszerzeń specyficznych dla Linuksa powinno być wyraźnie odnotowane, aby jakiś przyszły czytelnik nie próbował pomylić podobnego problemu w systemie innym niż Linux.
Andrew Henle
6
@AndrewHenle Ah, ciekawe! Zrobiłem szybki test ddna moim komputerze, z rozmiarami bloków od 1k do 512M. Odczyt z dysku SSD Intel 750, optymalna wydajność (około 1300 Mb / s) została osiągnięta przy blokach 2 MB, mniej więcej odpowiadając twoim wynikom. Większe rozmiary bloków nie pomagały ani nie przeszkadzały. Odczyt z /dev/zero, optymalna wydajność (prawie 20GiB / s) wynosiła 64KiB i 128KiB; zarówno mniejsze, jak i większe bloki zmniejszały wydajność, mniej więcej odpowiadając mojemu poprzedniemu komentarzowi. Konkluzja: punkt odniesienia dla Twojej aktualnej sytuacji. I oczywiście żadne z nas nie przeprowadziło testu porównawczego /dev/random: P
marcelm
3
@ Xen2050 Zrobiłem kilka ddszybszych testów i wygląda na to , że jest szybszy. Szybki przegląd pokazał, że headużywa odczytów 8KiB i dwóch zapisów 4KiB, co jest interesujące (GNU coreutils 8.26 w Debianie 9.6 / Linux 4.8). headprędkości są rzeczywiście gdzieś pomiędzy dd bs=4ka dd bs=8k. headprędkości spadają ~ 40% w porównaniu do dd if=/dev/zero bs=64ki spadają ~ 25% w porównaniu do dd if=/dev/nvme0n1 bs=2M. Odczyty z /dev/zerosą oczywiście bardziej ograniczone przez procesor, ale w przypadku SSD kolejkowanie we / wy również odgrywa pewną rolę. To większa różnica, niż się spodziewałem.
marcelm
21

ddmoże odczytać mniej niż ibs(uwaga: bsokreśla jedno ibsi drugie obs), chyba że iflag=fullblockpodano inaczej . 0+1 records inwskazuje, że 0pełne bloki i 1blok częściowy zostały odczytane. Jednak każdy pełny lub częściowy blok zwiększa licznik.

Nie znam dokładnego mechanizmu, który powoduje, że ddodczyt bloku jest mniejszy niż 1Gw tym konkretnym przypadku. Chyba jakikolwiek blok jest odczytywany do pamięci przed jego zapisaniem, więc zarządzanie pamięcią może przeszkadzać (ale to tylko przypuszczenie). Edycja: ta współbieżna odpowiedź wyjaśnia mechanizm, który powoduje, że ddodczyt bloku jest mniejszy niż 1Gw tym konkretnym przypadku.

W każdym razie nie polecam tak dużych bs. Chciałbym użyć bs=1M count=1024. Najważniejsze jest to: bez iflag=fullblock żadnej próby odczytu może odczytać mniej niż ibs(chyba ibs=1, że myślę, że jest to dość nieefektywne).

Więc jeśli chcesz odczytać dokładną ilość danych, użyj iflag=fullblock. Uwaga iflagnie jest wymagana przez POSIX, ddmożesz jej nie obsługiwać. Zgodnie z tą odpowiedzią ibs=1 jest to prawdopodobnie jedyny sposób POSIX-a na odczyt dokładnej liczby bajtów. Oczywiście, jeśli zmienisz ibs, będziesz musiał ponownie obliczyć count. W twoim przypadku obniżenie ibsdo 32Mlub mniej prawdopodobnie rozwiąże problem, nawet bez iflag=fullblock.

W moim Kubuntu naprawiłbym twoje polecenie w następujący sposób:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock
Kamil Maciorowski
źródło