Как я узнаю, что дд все еще работает?

147

Я не так ddуж много использовал, но пока это не подвело меня. Прямо сейчас у меня было ddболее 12 часов работы - я записываю образ обратно на диск, с которого он пришел - и я немного волнуюсь, так как я смог ddс диска на образ примерно 7 часов.

Я использую OSX 10.6.6 на MacBook с Core 2 Duo с частотой 2,1 ГГц / ядро ​​и 4 ГБ ОЗУ. Я читаю из .dmg на жестком диске со скоростью 7200 об / мин (загрузочный диск) и пишу на диск со скоростью 7200 об / мин, подключенный через разъем SATA-to-USB. Я оставил размер блока по умолчанию, и изображение составляет около 160 ГБ.

РЕДАКТИРОВАТЬ: И после 14 часов чистого стресса, в ddконце концов , работал отлично. В следующий раз, однако, я собираюсь прогнать его pvи отследить strace. Спасибо всем за вашу помощь.

eckza
источник
7
Не отвечая на ваш вопрос, но ваши времена довольно высоки IMO. Вы не забыли передать больший размер блока в dd, чем 512 байт по умолчанию? dd ... bs=16Mмое предложение, учитывая вашу оперативную память, размер диска и скорость.
Джулиано
Я не сделал, просто потому что я хотел быть осторожным. Я попробую это в следующий раз. Благодарю.
eckza
По моему опыту, ddв Mac OS X наблюдается тенденция зависать до такой степени, что я даже не могу убить процесс, но вынужден перезагружать систему. Тогда я прибегаю к работе на виртуальной машине Linux.
ssc

Ответы:

173

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

kill -INFO $PID

Вы можете найти идентификатор процесса ( $PIDвыше) с помощью psкоманды; или посмотрите альтернативы pgrep и pkill на Mac OS X для более удобных методов.

Проще говоря, как указывает AntoineG в своем ответе , вы можете набрать ctrl-Tв оболочке, запущенной dd, чтобы отправить ему INFOсигнал.

Например, в 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
Отправка dd сигнала USR1 слишком скоро после его запуска (т.е. в bash-скрипте, строка после того, как вы его запустили) фактически прекратит его. Поместите 0,1 секундный сон между ними, и он будет правильно выводить свой прогресс. Кстати, очень хорошая команда dd для тестирования USR1 / INFO dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow
11
Кстати, все «истинные» BSD отправляют SIGINFO в группу процессов переднего плана, если символ состояния (по умолчанию Ctrl + T) отправляется на терминал. Но я не знаю, правда ли это для MacOSX.
Нет
100

Под OS 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.

AntoineG
источник
1
О, хорошо, так loadчто использование процессора?
PJE
это было намного лучшее решение!
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
PV выглядит потрясающе - я определенно собираюсь использовать это в следующий раз. Огромное спасибо.
eckza
1
+1 - pvпохоже просто билет.
Boehj
17

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

РЕДАКТИРОВАТЬ: iotop -oпоказывать только программы, которые выполняют текущие операции ввода / вывода (спасибо Джейсону C за этот комментарий).

jofel
источник
1
Это мой предпочтительный метод быстрой проверки. iotop -oскроет процессы, которые не выполняют IO, и облегчит с первого взгляда, что происходит.
Джейсон C
13

Я обычно присоединяюсь straceк такому запущенному процессу (с -p $PIDвозможностью), чтобы видеть, остается ли он заблокированным в системном вызове или он все еще активен.

Или, если вы нервничаете по поводу отправки сигнала работающему дд, запустите другой дд, чтобы проверить, работает ли это.

philfr
источник
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

Начиная с coreutilsверсии 8.24, ddимеется встроенная поддержка для отображения прогресса. Просто добавьте опцию status=progress.

Пример:

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

Источник

Чираг Бхатия - чираг64
источник
5

ddrescue даст вам статистику, как он работает.

демо: http://www.youtube.com/watch?v=vqq9A01geeA#t=144s

Бен Престон
источник
3
Это может быть полезно в следующий раз, но это не поможет ОП понять, заморожена ли текущая команда или нет.
Франческо Турко
4

Иногда вы не сможете использовать сигнал INFO или USR1, потому что поток stderr 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с момента ее начала непрерывная запись с текущей средней скоростью записи. Если другие процессы конкурируют за ресурсы ЦП или В / В (включая шину В / В), это может снизить скорость передачи.

D Coetzee
источник
4

Я начал использовать dcfldd (1), который лучше показывает операции dd.

Картик М
источник
2

Пока ddвыполняется, я запускаю это в другом терминале от имени пользователя root:

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

Он печатает ddсостояние каждую 1 секунду в исходном окне терминала, где ddвыполняется, и завершает работу, когда команда выполнена.

ccpizza
источник
Так круто. Здесь отлично работали под Эль Капитаном
Стефано Мтангу
2

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

jofel
источник
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";
}
Леон Крамер
источник