Como sei se o dd ainda está funcionando?

147

Eu não usei ddmuito, mas até agora ainda não me falhou. No momento, eu trabalho ddhá mais de 12 horas - estou gravando uma imagem no disco de onde veio - e estou ficando um pouco preocupado, pois consegui dddo disco para a imagem em cerca de 7 horas.

Estou executando o OSX 10.6.6 em um MacBook com Core 2 Duo a 2,1ghz / core com 4GB de RAM. Estou lendo um arquivo .dmg em um disco rígido de 7200rpm (a unidade de inicialização) e estou gravando em uma unidade de 7200rpm conectada através de um conector SATA para USB. Deixei o tamanho do bloco como padrão e a imagem tem cerca de 160 gb.

EDIT: E, após 14 horas de puro estresse, ddfuncionou perfeitamente depois de tudo. Da próxima vez, porém, eu irei analisá-lo pve acompanhá-lo strace. Obrigado a todos por toda a sua ajuda.

eckza
fonte
7
Não estou respondendo sua pergunta, mas seus tempos são bastante altos. Você se lembrou de passar um tamanho de bloco maior para dd que não seja o padrão de 512 bytes? dd ... bs=16Mé minha sugestão, dada a sua RAM, tamanho e velocidade do disco.
Juliano
Não, simplesmente porque queria jogar pelo seguro. Vou tentar na próxima vez, no entanto. Obrigado.
eckza
Na minha experiência, ddno Mac OS X, a tendência é congelar até o ponto em que não consigo nem matar o processo, mas preciso reiniciar o sistema. Então, eu recorro ao trabalho em uma VM Linux.
ssc 12/06

Respostas:

173

Você pode enviar ddum determinado sinal usando o killcomando para fazer com que ele produza seu status atual. O sinal está INFOnos sistemas BSD (incluindo OSX) e USR1no Linux. No seu caso:

kill -INFO $PID

Você pode encontrar a identificação do processo ( $PIDacima) com o pscomando; ou consulte as alternativas pgrep e pkill no mac os x para obter métodos mais convenientes.

Mais simplesmente, como AntoineG aponta em sua resposta , você pode digitar ctrl-Tno shell executando dd para enviar o INFOsinal.

Como um exemplo no Linux, você pode fazer com que todos os ddprocessos ativos produzam status como este:

pkill -USR1 -x dd

Depois de emitir seu status, ddcontinuará enfrentando.

Caleb
fonte
9
Oh, muito legal. Você pode combiná-los compkill -USR1 -x dd
Michael Mrozek
9
@ kivetros: Nos sistemas BSD, você precisa enviar o INFOsinal. O Linux não possui um SIGINFO e utiliza USR1.
Gilles
5
Os sinais SIGUSRx são para os programas fazerem o que querem, em vez de ter um significado padronizado. O SIGWINCH, por exemplo, é gerado quando o terminal altera seu tamanho e o programa pode precisar redesenhar sua tela. O sistema operacional não envia SIGUSRx, portanto eles estão disponíveis para usos personalizados.
LawrenceC
11
Enviar dd o sinal USR1 muito cedo após o início (ou seja, em um script do bash, a linha após a sua inicialização) na verdade o encerrará. Coloque um sono de 0,1 segundo no meio e ele produzirá seu progresso corretamente. A propósito, um comando dd muito bom para testar o USR1 / INFO é dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow
11
BTW, todos os BSDs "verdadeiros" enviam SIGINFO ao grupo de processos em primeiro plano se o caractere de status (Ctrl + T por padrão) for enviado ao terminal. Mas não sei se isso é verdade para o MacOSX.
netch
100

No OS X (não tente no Linux), você pode simplesmente digitar Ctrl+ Tno terminal em execução dd. Ele imprimirá a mesma saída que kill -INFO $PID, além do uso da 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)

Descobri lendo este tópico e tentando abrir uma nova guia no meu terminal, mas misturando + Tcom Ctrl+ T.

AntoineG
fonte
1
Ah, ok, então loadé o uso da CPU?
pje 6/09/14
essa era uma solução muito melhor!
21315 Stephn_R
Eu tentei em dd no Linux, apenas ecoa ^Tpara o terminal.
precisa saber é o seguinte
1
certifique-se que você está fazendo ctrl + shift + T no terminal de mac
JBaczuk
26

Para dd, você pode enviar um sinal . Para outros comandos que estão lendo ou gravando em um arquivo, você pode observar a posição deles no arquivo lsof.

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

Se você planeja com antecedência, canalize os dados pv.

Gilles
fonte
1
pv parece incrível - eu definitivamente vou usá-lo na próxima vez. Muito obrigado.
eckza
1
+1 - pvparece apenas o bilhete.
boehj
17

Uma maneira mais geral é usar o iotopque exibe a quantidade atual de leitura / gravação em disco por programa.

EDIT: iotop -omostra apenas programas que realizam operações de E / S atualmente (agradecemos a Jason C por esse comentário).

jofel
fonte
1
Este é o meu método preferido de verificação rápida também. iotop -oocultará processos que não estão executando E / S e facilitará a visualização rápida do que está acontecendo.
Jason C
13

Eu costumo me conectar stracea esse processo em execução (com a -p $PIDopção) para ver se ele permanece bloqueado em uma chamada do sistema ou se ainda está ativo.

Ou, se você estiver nervoso por enviar um sinal para o dd em execução, inicie outro dd para validar se isso funciona.

philfr
fonte
2
Como exatamente você iria anexar strace? Além disso, eu comecei outro dde enviei um dos sinais sugeridos para ele, e ... ele o matou.
eckza
2
Se você conhece o pid do processo dd em execução, basta fazer o strace -p <pid>. Você deverá ver o registro de todas as chamadas de sistema chamados pelo processo (principalmente ler e escrever)
philfr
11

Para a próxima vez, você pode usar apenas pvdesde o início (se estiver disponível através do seu gerenciador de pacotes, instale-o). Este é um utilitário com o único objetivo de canalizar a entrada para a saída e monitorar o progresso e a velocidade.

Em seguida, para gravar uma imagem em uma unidade, digamos com tamanho de bloco de 4 MB:

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

Além do buffer inicial (compensado por uma sincronização final, que pode ser feita ddse você quiser), isso mostrará uma barra de progresso, velocidade média, velocidade atual e ETA.

A iflag=fullblockopção força o dd a pegar blocos completos de entrada pv, caso contrário, você estará à mercê do tubo para tamanhos de bloco.

Para ir para o outro lado, use dd para ler e pv para escrever, embora você precise especificar explicitamente o tamanho se a fonte for um dispositivo de bloco. Para um dispositivo de 4 GB:

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

Você também pode determinar o tamanho automaticamente, algo como:

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

Realmente não importa que ordem você faz dde pvem, é inteiramente relacionados com o desempenho - se o dispositivo que você está lendo de ou para tem um ótimo desempenho para determinados tamanhos de blocos que deseja usar ddem vez de pvacessar esse dispositivo. Você pode até colocar um dddos dois lados, se quiser, ou não, se não se importar:

pv -ptearb /path/to/image.bin > /dev/whatever
sync
Jason C
fonte
10

A partir da coreutilsv8.24, ddpossui suporte nativo para mostrar progresso. Basta adicionar a opção status=progress.

Exemplo:

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

Fonte

Chirag Bhatia - chirag64
fonte
5

ddrescue lhe fornecerá estatísticas enquanto estiver em execução.

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

Ben Preston
fonte
3
Isso pode ser útil para a próxima vez, mas não ajudará o OP a entender se o comando atual está congelado ou não.
Francesco Turco
4

Às vezes, você pode não conseguir usar o sinal INFO ou USR1 porque o fluxo stderr do ddprocesso não está acessível (por exemplo, porque o terminal no qual foi executado já estava fechado). Nesse caso, uma solução alternativa é fazer o seguinte (testado no FreeBSD, pode ser um pouco diferente no Linux):

  1. Use iostatpara estimar a taxa média de gravação (MB / s) no dispositivo de destino, por exemplo:

    iostat -d -w30 ada0

    Substitua o nome do dispositivo de destino por ada0aqui e aguarde alguns minutos para que ele dê alguns resultados. O parâmetro "w" determina quantos segundos entre as amostras. Aumentá-lo fornecerá uma estimativa média melhor com menos variação, mas você terá que esperar mais.

  2. Use pspara determinar há quanto tempo ddestá em execução:

    ps -xo etime,command | grep dd

    Converta isso em segundos para obter o total de segundos de tempo de execução.

  3. Multiplique o total de segundos de tempo de execução pela taxa média de gravação para obter o total de MB transferidos.
  4. Obtenha o tamanho do dispositivo em MB com:

    grep ada0 /var/run/dmesg.boot

    Substitua o nome do seu dispositivo de destino ada0. Divida o resultado pela taxa média de gravação para obter o tempo total de transferência em segundos. Subtraia o tempo que está sendo executado até agora para obter o tempo restante.

Essa estratégia só funciona se ddestiver gravando continuamente na taxa de gravação média atual desde o início. Se outros processos estiverem competindo pelos recursos da CPU ou de E / S (incluindo o barramento de E / S), isso poderá reduzir a taxa de transferência.

D Coetzee
fonte
4

Comecei a usar o dcfldd (1), que mostra as operações do dd de uma maneira melhor.

Kartik M
fonte
2

Enquanto ddestiver em execução, eu executo isso em outro terminal como root:

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

Ele imprime o ddstatus a cada 1 segundo na janela original do terminal em que ddestá sendo executado e fecha quando o comando é executado.

ccpizza
fonte
Tão legal. Funcionou bem aqui sob El Capitan
Stefano Mtangoo
2

Você pode usar o progressque, em particular, mostra o progresso de uma corrida dd. Ele usa /proc/$pid/fde /proc/$pid/fdinfo que você também pode monitorar manualmente.

jofel
fonte
1

A wcharlinha (caracteres escritos) em /proc/$pid/iopode fornecer informações precisas sobre o ddprocesso. Desde que mude, o seu ddainda está funcionando!

Aqui está um pequeno script php, que você pode salvar e executar php filename.phpdurante o ddpara exibir os bytes gravados. O benefício agradável de assistir /proc/$pid/iomais kill -USR1 $(pidof dd)é que você não tem que alternar entre os terminais, o que nem sempre é uma opção.

<?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
fonte