дд производит 32 МБ случайного файла вместо 1 ГБ

50

Я хотел создать случайный файл размером 1 ГБ, поэтому использовал следующую команду.

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

Но вместо этого каждый раз, когда я запускаю эту команду, я получаю файл размером 32 МБ:

<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

Что случилось?

РЕДАКТИРОВАТЬ:

Благодаря отличным ответам в этой теме я пришел с решением, которое читает 32 блока по 32 МБ, что составляет 1 ГБ:

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

Было дано другое решение, которое считывает 1 ГБ прямо в память, а затем записывает на диск. Это решение занимает много памяти, поэтому оно не является предпочтительным:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock
Трисмегиста
источник
3
ИМХО, я не думаю, что есть много действительных вариантов использования ddвообще. Я хотел бы использовать head, catили rsyncна его месте почти всегда. И ваш вопрос, если одна из причин, почему альтернативы, как правило, безопаснее.
Бакуриу
@Bakuriu - также, если вы просто хотите создать файл, полный нулей (или, скорее, вам все равно, что внутри него), используйте truncate. Это намного быстрее.
Конрад Гаевский
@KonradGajewski FYI усечение пытается создать разреженный файл (если это имеет значение)
Xen2050
5
@Bakuriu headне может выполнить эту задачу без -cопции, отсутствующей в POSIX . Я не знаю ни одной версии, catкоторая могла бы решить эту проблему. rsyncэто совершенно нестандартная утилита. Это ни здесь, ни здесь; Просматривая его справочную страницу, я тоже не вижу, как он может решить эту проблему.
Каз
Технически, /dev/urandomне в POSIX либо ...
grawity

Ответы:

94

bsРазмер буфера означает размер одиночного вызова read (), выполняемого dd.

(Например, и то bs=1M count=1и другое bs=1k count=1kприведет к файлу размером 1 МБ, но первая версия сделает это за один шаг, а вторая - за 1024 маленьких фрагмента.)

Обычные файлы могут быть прочитаны практически при любом размере буфера (при условии, что этот буфер помещается в ОЗУ), но устройства и «виртуальные» файлы часто работают очень близко к отдельным вызовам и имеют некоторые произвольные ограничения на объем данных, которые они будут создавать в чтение () вызов.

Для /dev/urandom, этот предел определен в urandom_read () в 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));
    ...
}

Это означает, что каждый раз, когда вызывается функция, она ограничивает запрошенный размер до 33554431 байта.

По умолчанию, в отличие от большинства других инструментов, dd не будет повторять попытки после получения меньшего количества данных, чем запрошено - вы получаете 32 МБ и все. (Чтобы сделать это автоматически, как в ответе Камила, вам нужно будет указать iflag=fullblock.)


Также обратите внимание, что «размер одного read ()» означает, что весь буфер должен помещаться в памяти одновременно, поэтому огромные размеры блоков также соответствуют массовому использованию памяти dd .

И все это бессмысленно, потому что вы обычно не получаете никакой производительности, когда превышаете ~ 16–32 МБ блоков - системные вызовы здесь не медленная часть, а генератор случайных чисел.

Так что для простоты просто используйте head -c 1G /dev/urandom > output.

grawity
источник
7
«... обычно вы не получаете никакой производительности, когда превышаете блоки размером ~ 16–32 МБ». По моему опыту, вы, как правило, не получаете много или даже теряете производительность выше 64–128 килобайт . В этот момент вы хорошо себя чувствуете в снижающихся доходах по сравнению с системными вызовами, и конфликт с кэшем начинает играть свою роль.
Marcelm
3
@marcelm Я помогал создавать высокопроизводительные системы, в которых производительность ввода-вывода улучшалась бы по мере увеличения размера блока до 1-2 МБ, а в некоторых случаях до 8 МБ или около того. За ЛУН. А поскольку файловые системы были построены с использованием нескольких параллельных LUN, для достижения максимальной производительности требовалось использовать несколько потоков для ввода-вывода, каждый из которых занимал 1 МБ + блоков. Поддерживаемые скорости ввода-вывода были более 1 ГБ / с. И все это были вращающиеся диски, поэтому я вижу высокопроизводительные массивы твердотельных накопителей, которые глотают или генерируют данные быстрее и быстрее, так как размер блока увеличивается до 16 или даже 32 МБ. Без труда. Может быть, даже больше.
Эндрю Хенле
4
Я прямо отмечу, что iflag=fullblockэто расширение GNU для утилиты POSIXdd . Поскольку вопрос не касается Linux, я думаю, что использование специфичных для Linux расширений, вероятно, следует четко отметить, чтобы не перепутать некоторых будущих читателей, пытающихся решить аналогичную проблему в системе, отличной от Linux.
Эндрю Хенле
6
@ AndrewHenle Ах, интересно! Я сделал быстрый тест ddна моей машине, с размерами блоков от 1k до 512M. При чтении с твердотельного накопителя Intel 750 оптимальная производительность (около 1300 МБ / с) была достигнута при блоках 2 МБ, что примерно соответствует вашим результатам. Большие размеры блоков ни помогали, ни мешали. При считывании /dev/zeroоптимальная производительность (почти 20 ГБ / с) была при блоках 64 КБ и 128 КБ; и меньшие, и большие блоки снизили производительность, что примерно соответствует моему предыдущему комментарию. Итог: ориентир для вашей реальной ситуации. И, конечно же, никто из нас не тестировал /dev/random: P
marcelm
3
@ Xen2050 Я сделал несколько более быстрых тестов, и, кажется dd, быстрее. Быстрый вывод показал, что headиспользуется чтение 8 КБ и две записи 4 КБ, что интересно (GNU coreutils 8.26 в Debian 9.6 / Linux 4.8). headскорости действительно где-то между dd bs=4kи dd bs=8k. headскорости снизились на ~ 40% по сравнению с dd if=/dev/zero bs=64kи на ~ 25% по сравнению с dd if=/dev/nvme0n1 bs=2M. Чтение из /dev/zero, конечно, более ограничено ЦП, но для SSD очередь ввода-вывода также играет роль. Это большая разница, чем я ожидал.
Marcelm
21

ddможет читать меньше ibs(примечание: bsуказывает оба ibsи obs), если iflag=fullblockне указано иное. 0+1 records inуказывает, что 0полные блоки и 1частичный блок были прочитаны. Однако любой полный или частичный блок увеличивает счетчик.

Я не знаю точный механизм, который делает ddчтение блока меньше, чем 1Gв данном конкретном случае. Я предполагаю, что любой блок считывается в память перед записью, поэтому управление памятью может помешать (но это только предположение). Изменить: этот параллельный ответ объясняет механизм, который делает ddчтение блока меньше, чем 1Gв данном конкретном случае.

Во всяком случае, я не рекомендую такой большой bs. Я бы использовал bs=1M count=1024. Самое главное: без iflag=fullblock какой-либо попытки чтения можно прочитать меньше, чем ibs(если ibs=1, я думаю, это не совсем эффективно).

Так что, если вам нужно прочитать какой-то точный объем данных, используйте iflag=fullblock. Примечание iflagне требуется POSIX, вы ddможете не поддерживать его. Согласно этому ответу ibs=1 , вероятно, единственный способ POSIX прочитать точное количество байтов. Конечно, если вы измените, ibsвам нужно будет пересчитать count. В вашем случае снижение ibsдо 32Mили меньше, вероятно, решит проблему, даже без iflag=fullblock.

В моем Kubuntu я бы исправил вашу команду следующим образом:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock
Камиль Мачоровски
источник