dd виробляє 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 - також, якщо ви просто хочете створити файл, заповнений нулями (а точніше, вам не байдуже, що знаходиться всередині нього), використовуйте скорочення. Це набагато швидше.
Конрад Гаєвський

@KonradGajewski FYI усікає намагається створити розріджений файл (якщо це має значення)
Xen2050

5
@Bakuriu headне може виконати це завдання без -cпараметра, якого немає в POSIX . Я не знаю, яка версія catможе це вирішити. rsync- це абсолютно нестандартна утиліта. Це ні тут немає; проглядаючи його сторінку, я також не бачу, як він може вирішити цю проблему.
Каз

Технічно /dev/urandomце не в POSIX ...
grawity

Відповіді:


92

bs, розмір буфера, означає розмір одного виклику read (), здійсненого dd.

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

Звичайні файли можна читати майже будь-якого розміру буфера (доки цей буфер вписується в оперативну пам’ять), але пристрої та "віртуальні" файли часто працюють дуже близько до окремих викликів і мають деяке довільне обмеження на кількість даних, які вони вироблять за читати () дзвінок.

Для /dev/urandomцього цей ліміт визначається в urandom_read () у драйверах / 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.)


Зауважимо також, що "розмір одного зчитування ()" означає, що весь буфер повинен вміщуватися в пам'яті відразу, тому масивні розміри блоків також відповідають масовому використанню пам'яті з боку dd .

І все безглуздо, тому що зазвичай ви не будете отримувати ніякої продуктивності при переході вище ~ 16–32 блоків MiB - систематичні дзвінки тут не є повільною частиною, генератор випадкових чисел.

Тому для простоти просто використовуйте head -c 1G /dev/urandom > output.


7
"... ти, як правило, не набереш ніякої продуктивності, переходячи на блоки більше 16-16 рублів МіБ" - На мій досвід, ти, як правило, не набираєш багато, а то й втрачаєш продуктивність понад 64-128 кілограмових байт. У цей момент ви добре знижуєте вартість зворотних системних викликів, і суперечки кешу починають грати роль.
marcelm

3
@marcelm Я допомагав архітекторам високопродуктивних систем, де продуктивність вводу-виводу покращувалася, оскільки розмір блоку збільшувався до 1-2 МБ блоків, а в деяких випадках і до 8 Мб. За ЛУН. Оскільки файлові системи були побудовані за допомогою декількох паралельних LUN, для досягнення найкращої продуктивності мається на увазі використання декількох потоків для вводу-виводу, кожна з яких робить 1 МБ + блоки. Стійкі частоти введення-виведення перевищували 1 Гб / сек. І все це були спінінгові диски, тому я можу бачити високопродуктивні масиви SSD, ковтаючи або генеруючи дані все швидше і швидше, оскільки розмір блоку збільшується до 16 або навіть 32 МБ блоків. Легко. Можливо, навіть більше.
Ендрю Генле

4
Я чітко зазначу, що iflag=fullblockце розширення GNU до утиліти POSIXdd . Оскільки питання не вказує Linux, я думаю, що використання розширень для Linux, можливо, слід чітко зазначити, щоб хтось із майбутніх читачів, які намагаються вирішити подібну проблему в нелінукс-системі, не заплутався.
Ендрю Генле

6
@AndrewHenle Ах, цікаво! Я зробив швидкий тест ddна своїй машині з розмірами блоків від 1k до 512M. Читання з Intel 750 SSD, оптимальна продуктивність (близько 1300 Мбіт / с) була досягнута в 2Мбіб-блоках, що приблизно відповідає вашим результатам. Більші розміри блоків ні допомогли, ні перешкодили. Читаючи з /dev/zero, оптимальна продуктивність (майже 20 Гбіт / с) була при блоках 64 КБ та 128 Кбіт; і менші, і більші блоки знижували продуктивність, що приблизно відповідає моєму попередньому коментарю. Підсумок: орієнтир для вашої фактичної ситуації. І звичайно, ніхто з нас не орієнтувався /dev/random: P
marcelm

3
@ Xen2050 Я зробив ще кілька швидких тестів, і виявляється, ddце швидше. Швидкий пробіг показав, що headвикористовується 8KiB зчитування, і два записи 4KiB, що цікаво (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. Примітка iflagPOSIX не потрібна, ddможливо, вона не підтримує її. Відповідно до цієї відповіді ibs=1 , мабуть, єдиний спосіб POSIX зчитувати точну кількість байтів. Звичайно, якщо ви змінитесь, ibsвам потрібно буде перерахувати count. У вашому випадку зниження ibsдо 32Mменш ймовірно , вирішити проблему, навіть без iflag=fullblock.

У своєму Kubuntu я би виправив вашу команду так:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.