Skąd mam wiedzieć, czy dd nadal działa?

147

Nie ddtyle zużyłem, ale na razie jeszcze mnie to nie zawiodło. W tej chwili mam ddponad 12 godzin - piszę obraz z powrotem na dysk, z którego pochodzi - i trochę się martwię, ponieważ mogłem ddz dysku na obraz około 7 godzin.

Używam OSX 10.6.6 na MacBooku z Core 2 Duo z prędkością 2,1 GHz / rdzeń z 4 GB pamięci RAM. Czytam z pliku .dmg na dysku twardym o prędkości 7200 obr / min (dysku rozruchowym) i piszę na dysku o prędkości 7200 obr / min podłączonego przez złącze SATA-USB. Domyślnie zostawiłem rozmiar bloku, a obraz ma około 160 GB.

EDYCJA: A po 14 godzinach czystego stresu wszystko dddziałało idealnie. Jednak następnym razem zamierzam go uruchomić pvi śledzić strace. Dziękujemy wszystkim za wszelką pomoc.

eckza
źródło
7
Nie odpowiadam na twoje pytanie, ale twoje czasy są dość wysokie IMO. Czy pamiętasz, aby przekazać dd większy rozmiar bloku niż domyślny 512 bajtów? dd ... bs=16Mto moja sugestia, biorąc pod uwagę pamięć RAM, rozmiar dysku i szybkość.
Juliano,
Nie zrobiłem tego, po prostu dlatego, że chciałem grać bezpiecznie. Spróbuję jednak następnym razem. Dzięki.
eckza
Z mojego doświadczenia ddwynika , że w systemie Mac OS X ma tendencję do zawieszania się do tego stopnia, że ​​nie mogę nawet zabić procesu, ale muszę zrestartować system. Następnie wykonuję pracę na maszynie wirtualnej z systemem Linux.
ssc

Odpowiedzi:

174

Możesz wysłać ddokreślony sygnał za pomocą killpolecenia, aby wyprowadził bieżący status. Sygnał jest INFOw systemach BSD (w tym OSX) i USR1Linux. W Twoim przypadku:

kill -INFO $PID

Identyfikator procesu można znaleźć ( $PIDpowyżej) za pomocą pspolecenia; lub zobacz alternatywne opcje pgrep i pkill na Mac OS X, aby uzyskać bardziej dogodne metody.

Mówiąc prościej, jak AntoineG wskazuje w swojej odpowiedzi , możesz pisać ctrl-Tw powłoce z uruchomionym dd, aby wysłać mu INFOsygnał.

Jako przykład w systemie Linux możesz ddustawić status wszystkich aktywnych procesów w następujący sposób:

pkill -USR1 -x dd

Po wyprowadzeniu jego statusu ddbędzie kontynuował kopiowanie.

Caleb
źródło
9
Och, bardzo fajnie. Możesz połączyć je zpkill -USR1 -x dd
Michael Mrozek
9
@kivetros: W systemach BSD należy wysłać INFOsygnał. Linux nie ma SIGINFO i USR1zamiast tego używa .
Gilles
5
Sygnały SIGUSRx służą programom do robienia tego, co chcą, zamiast mieć znormalizowane znaczenie. Na przykład SIGWINCH jest wywoływany, gdy terminal zmienił swój rozmiar, a program może wymagać przerysowania ekranu. System operacyjny nie wysyła SIGUSRx, więc są one dostępne do niestandardowych zastosowań.
LawrenceC
11
Wysłanie dd sygnału USR1 zbyt wcześnie po jego uruchomieniu (tj. W skrypcie bash, wiersz po uruchomieniu) faktycznie go zakończy. Po uśpieniu na 0,1 sekundy będzie on poprawnie wyświetlał swój postęp. Nawiasem mówiąc, bardzo fajnym poleceniem dd do testowania USR1 / INFO jest dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow
11
BTW, wszystkie „prawdziwe” BSD wysyłają SIGINFO do grupy procesów pierwszego planu, jeśli znak statusu (domyślnie Ctrl + T) jest wysyłany do terminala. Ale nie wiem, czy to prawda w MacOSX.
Netch
101

W systemie OS X (nie próbowałem w systemie Linux) możesz po prostu wpisać Ctrl+ Tw uruchomionym terminalu dd. Wyświetli to samo wyjście kill -INFO $PID, plus użycie procesora:

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)

Dowiedziałem się o tym czytając ten wątek i próbując otworzyć nową kartę w moim terminalu, ale mieszając + Tz Ctrl+ T.

AntoineG
źródło
1
Och, OK, więc loadużycie procesora?
pje
to było o wiele lepsze rozwiązanie!
Stephn_R
Próbowałem w dd na Linuksie, to po prostu odbija ^Tsię echem od terminala.
mwfearnley
1
upewnij się, że robisz ctrl + shift + T w terminalu mac
JBaczuk
26

Dla ddmożesz wysłać sygnał . W przypadku innych poleceń, które odczytują lub zapisują do pliku, możesz obserwować ich pozycję w pliku za pomocą lsof.

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

Jeśli planujesz z wyprzedzeniem, przeprowadź dane przez potok pv.

Gilles
źródło
1
pv wygląda niesamowicie - na pewno użyję tego następnym razem. Dziękuję bardzo.
eckza
1
+1 - pvwygląda jak bilet.
boehj
17

Bardziej ogólnym sposobem jest użycie, iotopktóre wyświetla bieżącą ilość odczytu / zapisu na dysku na program.

EDYCJA: iotop -opokazuje tylko programy, które wykonują obecnie operacje We / Wy (dziękuję Jasonowi C za ten komentarz).

Jofel
źródło
1
Jest to również moja preferowana metoda szybkiej kontroli. iotop -oukryje procesy, które nie działają we / wy i ułatwią szybkie sprawdzenie, co się dzieje.
Jason C
13

Zwykle dołączam się stracedo takiego uruchomionego procesu (z -p $PIDopcją), aby sprawdzić, czy pozostaje on zablokowany w wywołaniu systemowym, czy też jest nadal aktywny.

Lub jeśli denerwujesz się wysyłaniem sygnału do uruchomionego dd, uruchom kolejne dd, aby sprawdzić, czy to działa.

philfr
źródło
2
Jak dokładnie zająłbyś się dołączaniem strace? Również zacząłem inny ddi wysłałem mu jeden z sugerowanych sygnałów i ... to go zabiło.
eckza
2
Jeśli znasz pid uruchomionego procesu dd, po prostu wykonaj strace -p <pid>. Powinieneś zobaczyć dziennik wszystkich wywołań systemowych wywoływanych przez proces (głównie do odczytu i zapisu)
philfr
11

Następnym razem możesz po prostu użyć pvod samego początku (jeśli jest dostępny za pośrednictwem menedżera pakietów, zainstaluj go). Jest to narzędzie, którego jedynym celem jest przesyłanie danych wejściowych do wyjścia oraz monitorowanie postępu i prędkości.

Następnie, aby zapisać obraz na dysku, powiedzmy o rozmiarze bloku 4 MB:

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

Oprócz początkowego buforowania (przesuniętego przez ostateczną synchronizację, którą można wykonać, ddjeśli chcesz), pokaże Ci pasek postępu, średnią prędkość, aktualną prędkość i ETA.

Te iflag=fullblocksiły opcja dd chwycić pełne bloki wejścia przez pv, w przeciwnym razie jesteś na łasce rury na rozmiar bloku.

Aby przejść w drugą stronę, użyj dd do odczytu i pv do zapisu, chociaż musisz jawnie określić rozmiar, jeśli źródłem jest urządzenie blokowe. W przypadku urządzenia 4 GB:

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

Możesz również automatycznie określić rozmiar, na przykład:

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

Naprawdę nie ma znaczenia, w jakiej kolejności ddi pvw jakiej kolejności się zajmujesz , jest to całkowicie związane z wydajnością - jeśli urządzenie, z którego czytasz lub z którego odczytujesz, ma optymalną wydajność dla niektórych bloków, których chcesz użyć ddzamiast pvuzyskiwać dostęp do tego urządzenia. Możesz nawet przykleić ddoba końce, jeśli chcesz, lub wcale, jeśli nie zależy ci:

pv -ptearb /path/to/image.bin > /dev/whatever
sync
Jason C.
źródło
10

Począwszy od wersji coreutils8.24, ddma natywne wsparcie dla pokazywania postępu. Po prostu dodaj opcję status=progress.

Przykład:

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

Źródło

Chirag Bhatia - chirag64
źródło
5

ddrescue poda statystyki podczas działania.

demo: http://www.youtube.com/watch?v=vqq9A01geeA#t=144s

Ben Preston
źródło
3
Może to być pomocne następnym razem, ale nie pomoże OP zrozumieć, czy bieżące polecenie jest zawieszone, czy nie.
Francesco Turco
4

Czasami możesz nie być w stanie użyć sygnału INFO lub USR1, ponieważ strumień stderr ddprocesu nie jest dostępny (np. Ponieważ terminal, w którym został wykonany, był już zamknięty). W takim przypadku obejściem jest wykonanie następujących czynności (testowane na FreeBSD, mogą się nieco różnić w Linuksie):

  1. Służy iostatdo szacowania średniej prędkości zapisu (MB / s) na urządzeniu docelowym, np .:

    iostat -d -w30 ada0

    ada0Podaj tutaj nazwę urządzenia docelowego i poczekaj minutę, aż da kilka wyników. Parametr „w” określa liczbę sekund między próbkami. Zwiększenie go da lepsze średnie oszacowanie przy mniejszej wariancji, ale będziesz musiał czekać dłużej.

  2. Służy psdo określania ddczasu działania:

    ps -xo etime,command | grep dd

    Przelicz to na sekundy, aby uzyskać całkowitą liczbę sekund czasu wykonywania.

  3. Pomnóż całkowitą liczbę sekund środowiska wykonawczego przez średnią szybkość zapisu, aby uzyskać całkowitą przesłaną MB.
  4. Uzyskaj rozmiar urządzenia w MB dzięki:

    grep ada0 /var/run/dmesg.boot

    Zastąp nazwę urządzenia docelowego ada0. Podziel wynik przez średnią szybkość zapisu, aby uzyskać całkowity czas przesyłania w sekundach. Odejmij czas, który upłynął do tej pory, aby uzyskać pozostały czas.

Ta strategia działa tylko wtedy, gdy ddpisze nieprzerwanie z bieżącą średnią szybkością zapisu od początku. Jeśli inne procesy konkurują o zasoby procesora lub we / wy (w tym magistralę we / wy), może to zmniejszyć szybkość przesyłania.

D Coetzee
źródło
4

Zacząłem używać dcfldd (1), który lepiej pokazuje operacje dd.

Kartik M.
źródło
2

Podczas ddwykonywania uruchamiam to w innym terminalu jako root:

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

Drukuje ddstatus co 1 sekundę w oryginalnym oknie terminala, w którym ddjest wykonywany, i kończy działanie po wykonaniu polecenia.

ccpizza
źródło
Ale fajnie.
Świetnie działało
2

Możesz użyć, progressktóry w szczególności pokazuje postęp biegu dd. Wykorzystuje /proc/$pid/fdi /proc/$pid/fdinfo które można również monitorować ręcznie.

Jofel
źródło
1

wcharLinia (znaki napisane) w /proc/$pid/iomożna uzyskać dokładne informacje na temat ddprocesu. Tak długo, jak się zmienia, Twój ddnadal działa!

Oto schludny mały skrypt php, który można zapisać, a następnie wykonać php filename.phpza pomocą, ddaby wyświetlić zapisane bajty. Miła korzyść z oglądania /proc/$pid/iona kill -USR1 $(pidof dd)to, że nie trzeba przełączać się pomiędzy terminalami, co nie zawsze jest możliwe.

<?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";
}
Leon Kramer
źródło