Як я можу дізнатись, чи все ще працює АД?


147

Я так багато не використовував dd, але поки що це ще не провалило мене. Зараз у мене тривало ddпонад 12 годин - я записую зображення назад на диск, з якого він увійшов - і я трохи хвилююся, як мені вдалося ddз диска на зображення приблизно 7 годин.

Я працюю OSX 10.6.6 на MacBook із Core 2 Duo на 2,1 ГГц / ядро ​​з 4 ГБ оперативної пам’яті. Я читаю з .dmg на жорсткому диску 7200 об / хв (завантажувальний диск), і пишу на диск 7200 об / хв, підключений через роз'єм SATA-USB. Я залишив розмір блоку за замовчуванням, і зображення становить близько 160 Гб.

EDIT: І після 14 годин чистого стресу все-таки ddспрацювало чудово. Наступного разу, проте, я збираюся запустити його pvта відстежити strace. Дякую всім за вашу допомогу.


7
Не відповідаю на ваше запитання, але ваш час доволі високий ІМО. Чи пам’ятаєте ви передати більший розмір блоку до DD, окрім 512 байт за замовчуванням? dd ... bs=16M- це моя пропозиція, враховуючи вашу оперативну пам’ять, розмір та швидкість диска.
— Джуліано

Я цього не зробив, просто тому, що хотів захистити його. Я спробую це наступного разу, хоча. Дякую.
— eckza

На мій досвід, ddу Mac OS X є тенденція замерзати до того моменту, коли я навіть не можу вбити процес, але доведеться перезапустити систему. Тоді я вдаюсь до роботи над Linux VM.
— ssc

Відповіді:


174

Ви можете надіслати ddпевний сигнал за допомогою killкоманди, щоб зробити його поточним статусом. Сигнал подається INFOв системах BSD (включаючи OSX) та USR1в Linux. У вашому випадку:

kill -INFO $PID

Ви можете знайти ідентифікатор процесу ( $PIDвище) за допомогою psкоманди; або перегляньте альтернативи pgrep і pkill на mac os x для більш зручних методів.

Простіше кажучи, як в своїй відповіді вказує AntoineG , ви можете ввести оболонку, що працює під управлінням dd, щоб надіслати їй сигнал.ctrl-TINFO

Як приклад в Linux, ви можете зробити ddстатус активних процесів таким чином:

pkill -USR1 -x dd

Після виведення свого статусу ddпродовжить справлятися.


9
О, дуже круто. Можна поєднати їх ізpkill -USR1 -x dd
— Майкл Мрозек

9
@kivetros: У системах BSD вам потрібно надіслати INFOсигнал. У Linux немає SIGINFO і використовує USR1натомість.
— Жиль

5
Сигнали SIGUSRx призначені для програм робити те, що вони хочуть, на відміну від стандартизованого значення. Наприклад, SIGWINCH збільшується, коли термінал змінив свій розмір і програмі, можливо, доведеться перемалювати екран. Операційна система не надсилає SIGUSRx, тому вони доступні для користувальницького використання.
— LawrenceC

11
Надсилання сигналу USR1 занадто рано після його запуску (тобто у баш-скрипті, рядок після його запуску) насправді припинить його. Покладіть між собою сон на 0,1 секунди, і це нормально виведе його прогрес. До речі, дуже хороша команда dd для тестування USR1 / INFO на dd if=/dev/zero of=/dev/null. :)
— Lauritz V. Thaulow

11
До речі, всі "справжні" BSD передають SIGINFO групі процесу переднього плану, якщо символ стану (Ctrl + T за замовчуванням) надсилається до терміналу. Але я не знаю, чи правда це для MacOSX.
— Netch

101

У ОС X (не пробував Linux) ви можете просто ввести Ctrl+ Tу запущеному терміналі dd. Він надрукує такий самий вихід, як kill -INFO $PIDі використання процесора:

load: 1.40  cmd: dd 34536 uninterruptible 3.49u 64.58s
5020305+0 records in
5020304+0 records out
2570395648 bytes transferred in 4284.349974 secs (599950 bytes/sec)

Я дізнався про це, читаючи цю тему і намагався відкрити нову вкладку в своєму терміналі, але змішуючи ⌘+ Tз Ctrl+ T.


1
О, гаразд, так loadце використання процесора?
— пі

це було набагато кращим рішенням!
— Stephn_R

Я спробував у dd на Linux, це просто перегукується ^Tз терміналом.
— mwfearnley

1
переконайтеся, що ви робите ctrl + shift + T у mac-терміналі
— JBaczuk

26

Бо ddви можете надіслати сигнал . Для інших команд, які читають або записують у файл, ви можете переглянути їх положення у файлі за допомогою lsof.

lsof -o -p1234    # where 1234 is the process ID of the command
lsof -o /path/to/file

Якщо ви плануєте заздалегідь, передайте дані pv.


1
ПВ виглядає дивовижно - я обов'язково буду користуватися цим наступним разом. Дуже дякую.
— eckza

1
+1 - pvвиглядає як тільки квиток.
— boehj

17

Більш загальний спосіб - це використання, iotopякий відображає поточну кількість читання / запису диска на програму.

EDIT: iotop -oпоказуйте лише програми, які виконують в даний час операції вводу-виводу (дякую Джейсону С за цей коментар).


1
Це також мій кращий метод швидкої перевірки. iotop -oприховає процеси, які не роблять IO, і полегшить з першого погляду зрозуміти, що відбувається.
— Jason C

13

Зазвичай я приєднуюся straceдо такого запущеного процесу (з -p $PIDопцією), щоб побачити, чи він залишається заблокованим у системному дзвінку чи він все ще активний.

Або, якщо ви нервуєте надсилати сигнал до запущеного дд, почніть інший дд, щоб перевірити, якщо це працює.


2
Як саме ви б хотіли приєднатись strace? Також я запустив інший ddі надіслав йому один із запропонованих сигналів, і ... це вбив.
— eckza

2
Якщо ви знаєте pid запущеного процесу DD, просто зробіть strace -p <pid>. Ви повинні побачити журнал усіх системних дзвінків, викликаних процесом (здебільшого читання та запис)
— philfr

11

Наступного разу ви можете просто скористатися pvз самого початку (якщо це доступно через менеджера пакунків, встановіть його). Це утиліта з єдиною метою трубопроводу введення для виводу та моніторингу ходу та швидкості.

Потім, для запису зображення на диск, скажіть із розміром блоку 4 Мб:

pv -ptearb /path/to/image.bin | dd iflag=fullblock of=/dev/whatever bs=4M

Окрім початкового буферизації (компенсується остаточною синхронізацією, яку можна здійснити, ddякщо хочете), це покаже вам смугу прогресу, середню швидкість, поточну швидкість та ETA.

В iflag=fullblockопції сили д.д. , щоб захопити повні блоки введення через pv, в іншому випадку ви на милість труби для розмірів блоків.

Щоб піти в інший спосіб, використовуйте dd для читання та pv для запису, хоча вам потрібно чітко вказати розмір, якщо джерело - це блок-пристрій. Для пристрою об'ємом 4 Гб:

dd if=/dev/whatever bs=4M | pv -ptearb -s 4096m > /path/to/image.bin

Ви також можете визначити розмір автоматично, приблизно так:

dd if=/dev/whatever bs=4M | pv -ptearb -s `blockdev --getsize64 /dev/whatever` > /path/to/image.bin

Насправді не має значення, який ви замовляєте ddта pvв якому режимі, це повністю пов’язано з продуктивністю - якщо пристрій, якому ви читаєте або з якого, має оптимальну продуктивність для певних блочних розмірів, які ви хочете використовувати ddзамість pvдоступу до цього пристрою. Ви навіть можете приклеїти ddобох кінців, якщо хочете, або взагалі, якщо вам все одно:

pv -ptearb /path/to/image.bin > /dev/whatever
sync

10

Станом на coreutilsv8.24, ddмає вбудовану підтримку для показу прогресу. Просто додайте варіант status=progress.

Приклад:

dd if=arch.iso of=/dev/sdb bs=4M status=progress

Джерело



4

Іноді, можливо, ви не зможете використовувати сигнал INFO або USR1, тому що струменевий потік ddпроцесу недоступний (наприклад, через те, що термінал, в якому він був виконаний, уже закритий). У цьому випадку вирішення завдання полягає в тому, щоб виконати наступні дії (тестовані на FreeBSD, можливо, вони дещо відрізняються в Linux):

  1. Використовуйте iostatдля оцінки середньої швидкості запису (МБ / с) для цільового пристрою, наприклад:

    iostat -d -w30 ada0

    Замініть ім'я свого цільового пристрою ada0тут і почекайте хвилину, щоб він дав пару результатів. Параметр "w" визначає скільки секунд між зразками. Підвищення його дасть кращу середню оцінку з меншою дисперсією, але вам доведеться почекати довше.

  2. Використовуйте, psщоб визначити, як довго ddпрацює:

    ps -xo etime,command | grep dd

    Перетворіть це в секунди, щоб отримати загальну секунду часу виконання.

  3. Помножте загальну секунду часу виконання на середню швидкість запису, щоб отримати загальну передану МБ.
  4. Отримайте розмір пристрою в МБ за допомогою:

    grep ada0 /var/run/dmesg.boot

    Замініть ім'я цільового пристрою ada0. Результат розділіть на середню швидкість запису, щоб отримати загальний час передачі в секундах. Відніміть час, який він працював до цього часу, щоб залишитися час.

Ця стратегія працює лише в тому випадку, якщо ddз моменту її початку пишеться постійно з поточною середньою швидкістю запису. Якщо інші ресурси конкурують за ресурси ЦП або вводу / виводу (включаючи шину вводу / виводу), це може знизити швидкість передачі.



2

Під час ddвиконання, я запускаю це в іншому терміналі як root:

while pgrep ^dd; do pkill -INFO dd; sleep 1; done

Він друкує ddстан кожні 1 секунду у вихідному вікні терміналу, де ddвиконується, і закриває, коли команда виконана.


Так кльово. Тут добре працював під Ель-Капітан
— Стефано Мтангу

2

Ви можете використовувати, progressщо, зокрема, показує хід бігу dd. Він використовує /proc/$pid/fdі /proc/$pid/fdinfo який ви також можете контролювати вручну.


1

wchar(Письмових знаків) в рядку /proc/$pid/ioможе дати точну інформацію про ddпроцесі. Поки вона змінюється, ваша ddвсе ще працює!

Ось акуратний маленький скрипт для php, який ви можете зберегти, а потім виконати за допомогою php filename.phpпід час ddвідображення написаних байтів. Хороша користь від перегляду /proc/$pid/ioбільш kill -USR1 $(pidof dd), що вам не доведеться перемикатися між терміналами, що не завжди варіант.

<?php

/** Time between refreshs in seconds */
$refresh = 1;


/**
 * Start of Script 
 */

if (!($pid = exec('pidof dd')))
    exit("no dd running\n");

$history = array();
$break_ms = $refresh * 1000000;
$start_time = exec("ls -ld /proc/$pid --time-style=+\"%s\" | egrep -o [0-9]{10}");


fprintf(STDOUT, "PID: %s\n", $pid);
fprintf(STDOUT, "START TIME: %s\n\n", date("Y-m-d H:i:s", $start_time));


while (true) {
    if (isset($curr))
        array_push($history, $curr);

    if (count($history) > 10) array_shift($history);
    $oldest = reset($history);
    $latest = end($history);

    /**
     * get number of written bytes from /proc/$pid/io
     */
    #if (!($curr = exec("cat /proc/$pid/io | grep ^write_bytes | sed 's/write_bytes: //g'")))
    #    break;

    /* prepare proc_open() parameter */
    $descriptorspec = array(
        0 => array('pipe', 'r'), // stdin
        1 => array('pipe', 'w'), // stdout
        2 => array('pipe', 'w'), // stderr
    );

    $process = proc_open("cat /proc/$pid/io | grep ^write_bytes | sed 's/write_bytes: //g'", $descriptorspec, $pipes);
    if (!is_resource($process)) break;

    $stdout = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    proc_close($process);

    if (!empty($stderr)) break;
    $curr = trim($stdout);

    /**
     * caculate elapsed time from start */
    $time_elapsed = time() - $start_time;

    /**
     * avg speed since start */
    $avg = $time_elapsed > 0 ? round($curr / $time_elapsed) : 0;

    /**
     * avg speed of last 10 updates */
    if (count($history) > 0)
        $speed = human_file_size(round(($latest - $oldest) / count($history) / $refresh));

    $output = sprintf("\rBYTES WRITTEN: %s [%s]  ::  CURRENT: %s/s  ::  AVERAGE: %s/s  ::  ELAPSED: %s", $curr, human_file_size($curr), isset($speed) ? $speed : 0, human_file_size($avg), gmdate("H:i:s", $time_elapsed));
    printf("%s%s", $output, str_repeat(" ", exec("tput cols") - strlen($output)));

    usleep($break_ms);
}

fprintf(STDOUT, "\ndd has finished!\n\n");

function human_file_size($size,$unit="") {
  if( (!$unit && $size >= 1<<30) || $unit == "GB")
    return number_format($size/(1<<30),2)." GB";
  if( (!$unit && $size >= 1<<20) || $unit == "MB")
    return number_format($size/(1<<20),2)." MB";
  if( (!$unit && $size >= 1<<10) || $unit == "kB")
    return number_format($size/(1<<10),2)." kB";
  return number_format($size)." bytes";
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.