¿Cómo sé si dd aún funciona?


147

No he usado ddtanto, pero hasta ahora no me ha fallado. En este momento, he estado en ddfuncionamiento durante más de 12 horas, estoy escribiendo una imagen en el disco de donde vino, y me estoy preocupando un poco, ya que pude dddesde el disco a la imagen en aproximadamente 7 horas.

Estoy ejecutando OSX 10.6.6 en una MacBook con un Core 2 Duo a 2.1 ghz / core con 4 gb de RAM. Estoy leyendo desde un .dmg en un disco duro de 7200 rpm (la unidad de arranque), y estoy escribiendo en una unidad de 7200 rpm conectada a través de un conector SATA a USB. Dejé el tamaño de bloque predeterminado, y la imagen es de aproximadamente 160 gb.

EDITAR: Y, después de 14 horas de puro estrés, ddfuncionó perfectamente después de todo. La próxima vez, sin embargo, voy a analizarlo pvy rastrearlo strace. Gracias a todos por toda su ayuda.


77
No responde a su pregunta, pero sus tiempos son bastante altos. ¿Recuerdas pasar un tamaño de bloque más grande a dd que no sea el predeterminado 512 bytes? dd ... bs=16Mes mi sugerencia, dada su RAM, tamaño de disco y velocidad.
Juliano

No lo hice, simplemente porque quería jugar a lo seguro. Aunque lo intentaré la próxima vez. Gracias.
eckza

En mi experiencia, dden Mac OS X tiene una tendencia a congelarse hasta el punto en que ni siquiera puedo matar el proceso, pero tengo que reiniciar el sistema. Entonces recurro a trabajar en una máquina virtual Linux.
ssc

Respuestas:


173

Puede enviar dduna determinada señal utilizando el killcomando para que emita su estado actual. La señal está INFOen sistemas BSD (incluido OSX) y USR1en Linux. En tu caso:

kill -INFO $PID

Puede encontrar la identificación del proceso ( $PIDarriba) con el pscomando; o vea las alternativas pgrep y pkill en mac os x para obtener métodos más convenientes.

Más simplemente, como señala AntoineG en su respuesta , puede escribir ctrl-Ten el shell que ejecuta dd para enviarle la INFOseñal.

Como ejemplo en Linux, puede hacer que todos los ddprocesos activos muestren un estado como este:

pkill -USR1 -x dd

Después de mostrar su estado, ddcontinuará haciendo frente.


99
Oh, muy bien Puedes combinarlos conpkill -USR1 -x dd
Michael Mrozek

99
@kivetros: en los sistemas BSD, debe enviar la INFOseñal. Linux no tiene un SIGINFO y utiliza en su USR1lugar.
Gilles

55
Las señales SIGUSRx son para que los programas hagan lo que quieran, en lugar de tener un significado estandarizado. SIGWINCH, por ejemplo, se genera cuando el terminal ha cambiado su tamaño y el programa puede necesitar redibujar su pantalla. El sistema operativo no envía SIGUSRx, por lo que están disponibles para usos personalizados.
LawrenceC

11
Enviar dd la señal USR1 demasiado pronto después de que haya comenzado (es decir, en un script bash, la línea después de que la haya iniciado), de hecho, la terminará. Ponga un sueño de 0.1 segundos en el medio y generará su progreso correctamente. Por cierto, es un buen comando dd para probar USR1 / INFO dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow

11
Por cierto, todos los BSD "verdaderos" envían SIGINFO al grupo de procesos en primer plano si el carácter de estado (Ctrl + T por defecto) se envía al terminal. Pero no sé si es cierto para MacOSX.
Netch

100

Bajo OS X (no probé en Linux), simplemente puede escribir Ctrl+ Ten el terminal en ejecución dd. Imprimirá el mismo resultado que kill -INFO $PID, más el uso de la 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)

Me enteré leyendo este hilo e intentando abrir una nueva pestaña en mi terminal pero mezclando + Tcon Ctrl+ T.


1
Oh, está bien, ¿así loades el uso de la CPU?
pje

¡Esta fue una solución mucho mejor!
Stephn_R

Intenté en dd en Linux, solo hace eco ^Ten el terminal.
mwfearnley

1
asegúrese de que está haciendo ctrl + shift + T en la terminal mac
JBaczuk

26

Para dd, puede enviar una señal . Para otros comandos que leen o escriben en un archivo, puede ver su posición en el archivo con lsof.

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

Si planifica con anticipación, canalice los datos pv.


1
pv se ve increíble, definitivamente voy a usar eso la próxima vez. Muchas gracias.
eckza

1
+1: pvparece solo el boleto.
boehj

17

Una forma más general es usar una iotoppantalla que muestre la cantidad actual de lectura / escritura de disco por programa.

EDITAR: iotop -omuestra solo los programas que realizan actualmente operaciones de E / S (gracias Jason C por este comentario).


1
Este es mi método de verificación rápida preferido también. iotop -oocultará los procesos que no están haciendo IO y hará que sea más fácil decir de un vistazo lo que está sucediendo.
Jason C

13

Por lo general, me adjunto stracea dicho proceso en ejecución (con la -p $PIDopción) para ver si permanece bloqueado en una llamada al sistema o si todavía está activo.

O, si se siente nervioso por enviar una señal al dd en ejecución, inicie otro dd para validar si esto funciona.


2
¿Cómo exactamente harías para unir strace? Además, comencé otro ddy le envié una de las señales sugeridas, y ... lo mató.
eckza

2
Si conoce el pid del proceso dd en ejecución, simplemente ejecute strace -p <pid>. Debería ver el registro de todas las llamadas al sistema llamadas por el proceso (principalmente lectura y escritura)
philfr

11

Para la próxima vez, puede usarlo pvdesde el principio (si está disponible a través de su administrador de paquetes, instálelo). Esta es una utilidad con el único propósito de canalizar la entrada a la salida y monitorear el progreso y la velocidad.

Luego, para escribir una imagen en una unidad, digamos con un tamaño de bloque de 4 MB:

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

Además del almacenamiento en búfer inicial (compensado por una sincronización final, que se puede hacer ddsi lo desea), esto le mostrará una barra de progreso, velocidad promedio, velocidad actual y ETA.

La iflag=fullblockopción obliga a dd a capturar bloques completos de entrada pv, de lo contrario estará a merced de la tubería para los tamaños de bloque.

Para ir hacia el otro lado, use dd para leer y pv para escribir, aunque debe especificar explícitamente el tamaño si la fuente es un dispositivo de bloque. Para un dispositivo de 4 GB:

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

También puede determinar el tamaño automáticamente, algo como:

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

Realmente no importa en qué orden lo haga ddy pvestá completamente relacionado con el rendimiento: si el dispositivo al que está leyendo o desde el que tiene un rendimiento óptimo para ciertos bloques que desea usar en ddlugar de pvacceder a ese dispositivo. Incluso puede pegar un ddextremo en ambos extremos si lo desea, o no hacerlo si no le importa:

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

10

A partir de coreutilsv8.24, ddtiene soporte nativo para mostrar el progreso. Solo agrega la opción status=progress.

Ejemplo:

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

Fuente



4

A veces es posible que no pueda utilizar la señal INFO o USR1 porque el flujo stderr del ddproceso no es accesible (por ejemplo, porque el terminal en el que se ejecutó ya estaba cerrado). En este caso, una solución consiste en hacer lo siguiente (probado en FreeBSD, puede ser ligeramente diferente en Linux):

  1. Se usa iostatpara estimar la tasa de escritura promedio (MB / s) en el dispositivo de destino, por ejemplo:

    iostat -d -w30 ada0

    Sustituya el nombre del dispositivo de destino por ada0aquí y espere un minuto para que le dé un par de resultados. El parámetro "w" determina cuántos segundos entre muestras. Aumentarlo dará una mejor estimación promedio con menos varianza, pero tendrá que esperar más.

  2. Use pspara determinar cuánto tiempo ddha estado funcionando:

    ps -xo etime,command | grep dd

    Convierta esto a segundos para obtener el total de segundos de tiempo de ejecución.

  3. Multiplique el total de segundos de tiempo de ejecución por la tasa de escritura promedio para obtener el total de MB transferidos.
  4. Obtenga el tamaño del dispositivo en MB con:

    grep ada0 /var/run/dmesg.boot

    Sustituya el nombre del dispositivo de destino por ada0. Divida el resultado por la tasa de escritura promedio para obtener el tiempo de transferencia total en segundos. Reste el tiempo que ha estado funcionando hasta ahora para obtener el tiempo restante.

Esta estrategia solo funciona si ddha estado escribiendo continuamente a la tasa de escritura promedio actual desde que comenzó. Si otros procesos compiten por la CPU o los recursos de E / S (incluido el bus de E / S), entonces puede reducir la velocidad de transferencia.


4

Empecé a usar dcfldd (1), que muestra las operaciones dd de una mejor manera.


2

Mientras ddse ejecuta, ejecuto esto en otra terminal como root:

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

Imprime el ddestado cada 1 segundo en la ventana de terminal original donde se ddestá ejecutando, y se cierra cuando finaliza el comando.


Muy guay. Funcionó bien aquí bajo El Capitán
Stefano Mtangoo

2

Puede usar lo progressque, en particular, muestra el progreso de una carrera dd. Utiliza /proc/$pid/fdy /proc/$pid/fdinfo que también puede monitorear a mano.


1

La wcharlínea (caracteres escritos) /proc/$pid/iopuede brindarle información precisa sobre el ddproceso. Mientras cambie, ¡ ddtodavía está funcionando!

Aquí hay un pequeño script PHP ordenado, que puede guardar y luego ejecutar php filename.phpdurante ddpara mostrar los bytes escritos. La ventaja agradable de ver /proc/$pid/iomás kill -USR1 $(pidof dd)es que usted no tiene que cambiar entre terminales, que no es siempre una opción.

<?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";
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.