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


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.