Come faccio a sapere se dd funziona ancora?


147

Non ho usato ddmolto, ma finora non mi ha ancora deluso. In questo momento, ho provato ddper più di 12 ore - sto scrivendo un'immagine sul disco da cui proviene - e mi sto preoccupando un po ', dato che sono stato in grado di passare dddal disco all'immagine in circa 7 ore.

Sto eseguendo OSX 10.6.6 su un MacBook con un Core 2 Duo a 2.1ghz / core con 4 GB di RAM. Sto leggendo da un .dmg su un disco rigido a 7200 rpm (l'unità di avvio) e sto scrivendo su un'unità a 7200 rpm collegata tramite un connettore SATA-USB. Ho lasciato la dimensione di blocco predefinita e l'immagine è di circa 160 GB.

EDIT: E, dopo 14 ore di puro stress, dddopo tutto ha funzionato perfettamente. La prossima volta, però, lo eseguirò pve lo seguirò strace. Grazie a tutti per tutto il vostro aiuto.


7
Non rispondere alla tua domanda, ma i tuoi tempi sono abbastanza alti IMO. Ti sei ricordato di passare una dimensione di blocco più grande a dd diverso dai 512 byte predefiniti? dd ... bs=16Mè il mio suggerimento, data la tua RAM, dimensione del disco e velocità.
Juliano,

Non l'ho fatto, semplicemente perché volevo giocare sul sicuro. Ci proverò la prossima volta, però. Grazie.
eckza,

Nella mia esperienza, ddsu Mac OS X ha la tendenza a congelare al punto in cui non riesco nemmeno a interrompere il processo, ma devo riavviare il sistema. Quindi ricorro a lavorare su una VM Linux.
ssc,

Risposte:


173

È possibile inviare ddun determinato segnale utilizzando il killcomando per farlo emettere il suo stato corrente. Il segnale è INFOsu sistemi BSD (incluso OSX) e USR1su Linux. Nel tuo caso:

kill -INFO $PID

Puoi trovare l'id del processo ( $PIDsopra) con il pscomando; oppure vedi le alternative pgrep e pkill su mac os x per metodi più convenienti.

Più semplicemente, come sottolinea AntoineG nella sua risposta , è possibile digitare ctrl-Tsulla shell che esegue dd per inviare il INFOsegnale.

Ad esempio su Linux, è possibile rendere tutti i ddprocessi attivi in output lo stato in questo modo:

pkill -USR1 -x dd

Dopo aver emesso il suo stato, ddcontinuerà a far fronte.


9
Oh, molto bene. Puoi combinare quelli conpkill -USR1 -x dd
Michael Mrozek

9
@kivetros: sui sistemi BSD, è necessario inviare il INFOsegnale. Linux non ha un SIGINFO e usa USR1invece.
Gilles,

5
I segnali SIGUSRx sono per i programmi per fare ciò che vogliono, invece di avere un significato standardizzato. SIGWINCH, ad esempio, viene generato quando il terminale ha cambiato dimensione e il programma potrebbe dover ridisegnare lo schermo. Il sistema operativo non invia i SIGUSRx, quindi sono disponibili per usi personalizzati.
LawrenceC

11
L'invio del segnale USR1 troppo presto dopo l'avvio (ovvero in uno script bash, la riga dopo averlo avviato) lo interromperà di fatto. Metti un sonno di 0,1 secondi in mezzo e produrrà i suoi progressi correttamente. A proposito, è un ottimo comando dd per testare USR1 / INFO dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow,

11
A proposito, tutti i BSD "veri" inviano SIGINFO al gruppo di processi in primo piano se il carattere di stato (Ctrl + T di default) viene inviato al terminale. Ma non so se sia vero per MacOSX.
Netch

100

Sotto OS X (non ho provato su Linux), puoi semplicemente digitare Ctrl+ Tnel terminale in esecuzione dd. Stampa lo stesso output di kill -INFO $PID, oltre all'utilizzo della CPU:

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)

L'ho scoperto leggendo questo thread e provando ad aprire una nuova scheda nel mio terminale ma mescolando + Tcon Ctrl+ T.


1
Oh, ok, quindi loadè l'utilizzo della CPU?
pje,

questa era davvero una soluzione migliore!
Stephn_R,

Ho provato in dd su Linux, fa eco solo ^Tal terminale.
mwfearnley,

1
assicurati di fare ctrl +
maiusc

26

Per dd, è possibile inviare un segnale . Per altri comandi che stanno leggendo o scrivendo su un file, puoi guardare la loro posizione nel file con lsof.

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

Se pianifichi in anticipo, reindirizza i dati pv.


1
pv sembra fantastico - lo userò sicuramente la prossima volta. Grazie mille.
eckza,

1
+1: pvsembra solo il biglietto.
Boehj,

17

Un modo più generale è quello di utilizzare la iotopvisualizzazione della quantità corrente di lettura / scrittura del disco per programma.

EDIT: iotop -omostra solo i programmi che eseguono attualmente operazioni di I / O (grazie Jason C per questo commento).


1
Questo è anche il mio metodo di controllo rapido preferito. iotop -onasconderà i processi che non stanno eseguendo IO e renderà più facile capire a colpo d'occhio cosa sta succedendo.
Jason C,

13

Di solito mi collego stracea tale processo in esecuzione (con l' -p $PIDopzione) per vedere se rimane bloccato in una chiamata di sistema o se è ancora attivo.

Oppure, se ti senti nervoso per l'invio di un segnale al dd in esecuzione, avvia un altro dd per confermare se funziona.


2
Come faresti esattamente per attaccare strace? Inoltre, ne ho fatto partire un altro dde gli ho inviato uno dei segnali suggeriti, e ... l'ha ucciso.
eckza,

2
Se conosci il pid del processo dd in esecuzione, esegui semplicemente strace -p <pid>. Dovresti vedere il registro di tutte le chiamate di sistema chiamate dal processo (principalmente leggere e scrivere)
philfr

11

Per la prossima volta, puoi semplicemente usarlo pvdall'inizio (se è disponibile tramite il tuo gestore pacchetti, installalo). Questa è un'utilità con il solo scopo di convogliare l'input all'output e monitorare l'avanzamento e la velocità.

Quindi, per scrivere un'immagine su un'unità, dire con una dimensione di blocco di 4 MB:

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

A parte il buffering iniziale (compensato da una sincronizzazione finale, che può essere eseguita ddse lo desideri), questo ti mostrerà una barra di avanzamento, velocità media, velocità corrente ed ETA.

L' iflag=fullblockopzione forza dd ad afferrare interi blocchi di input pv, altrimenti sei in balia del tubo per le dimensioni dei blocchi.

Per andare dall'altra parte usa dd per leggere e pv per scrivere, anche se devi specificare esplicitamente la dimensione se l'origine è un dispositivo a blocchi. Per un dispositivo da 4 GB:

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

Puoi anche determinare automaticamente le dimensioni, qualcosa del tipo:

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

In realtà non importa in che ordine fai dde pvin, è interamente legato alle prestazioni - se il dispositivo che stai leggendo o da cui ha prestazioni ottimali per determinate dimensioni di blocchi che desideri utilizzare ddinvece di pvaccedere a quel dispositivo. Puoi anche attaccare dda entrambe le estremità se vuoi, o per niente se non ti interessa:

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

10

A partire dalla coreutilsv8.24, ddha il supporto nativo per mostrare i progressi. Aggiungi solo l'opzione status=progress.

Esempio:

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

fonte



4

A volte potresti non essere in grado di utilizzare il segnale INFO o USR1 perché il flusso stderr del ddprocesso non è accessibile (ad esempio perché il terminale in cui è stato eseguito era già chiuso). In questo caso, una soluzione alternativa consiste nel fare quanto segue (testato su FreeBSD, potrebbe essere leggermente diverso su Linux):

  1. Utilizzare iostatper stimare la velocità di scrittura media (MB / s) sul dispositivo di destinazione, ad esempio:

    iostat -d -w30 ada0

    Sostituisci qui il nome del tuo dispositivo di destinazione ada0e attendi un minuto per ottenere un paio di risultati. Il parametro "w" determina quanti secondi tra i campioni. Aumentandolo si otterrà una stima media migliore con meno varianze, ma dovrai aspettare più a lungo.

  2. Utilizzare psper determinare da quanto tempo ddè in esecuzione:

    ps -xo etime,command | grep dd

    Converti questo in secondi per ottenere secondi totali di runtime.

  3. Moltiplicare i secondi totali di runtime per la velocità di scrittura media per ottenere MB totali trasferiti.
  4. Ottieni le dimensioni del dispositivo in MB con:

    grep ada0 /var/run/dmesg.boot

    Sostituisci il nome del tuo dispositivo di destinazione per ada0. Dividi il risultato per la velocità di scrittura media per ottenere il tempo di trasferimento totale in secondi. Sottrai il tempo che è stato eseguito finora per ottenere il tempo rimanente.

Questa strategia funziona solo se ddha scritto continuamente alla velocità di scrittura media corrente da quando è iniziata. Se altri processi sono in competizione per le risorse CPU o I / O (incluso il bus I / O), è possibile che la velocità di trasferimento venga ridotta.


4

Ho iniziato a usare dcfldd (1), che mostra le operazioni dd in un modo migliore.


2

Durante l' ddesecuzione, eseguo questo in un altro terminale come root:

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

Stampa lo ddstato ogni 1 secondo nella finestra del terminale originale in cui ddè in esecuzione e si chiude al termine del comando.


Così fico. Ha funzionato bene qui sotto El Capitan
Stefano Mtangoo,

2

È possibile utilizzare progressche, in particolare, mostra l'avanzamento di una corsa dd. Utilizza /proc/$pid/fde /proc/$pid/fdinfo che puoi anche monitorare a mano.


1

La wcharriga (caratteri scritti) in /proc/$pid/iopuò darti informazioni precise sul ddprocesso. Finché cambia, il tuo ddfunziona ancora!

Ecco un piccolo script php pulito, che puoi salvare e quindi eseguire php filename.phpdurante il ddper visualizzare i byte scritti. Il bel vantaggio di guardare /proc/$pid/iooltre kill -USR1 $(pidof dd)è che non c'è bisogno di passare tra i terminali, che non è sempre un'opzione.

<?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";
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.