Como sei se o dd ainda está funcionando?

141

Eu não usei dd tanto assim, mas até agora não me falhou ainda. No momento, eu tive um dd por mais de 12 horas - estou escrevendo uma imagem de volta para o disco de onde veio - e estou ficando um pouco preocupado, já que consegui dd do disco para a imagem em cerca de 7 horas.

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

EDIT: E, depois de 14 horas de puro estresse, o dd funcionou perfeitamente depois de tudo. Da próxima vez, no entanto, vou executá-lo em pv e rastreá-lo com strace . Obrigado a todos por toda sua ajuda.

    
por eckza 13.04.2011 / 19:19

13 respostas

166

Você pode enviar dd um certo sinal usando o comando kill para fazer com que ele exiba seu status atual. O sinal é INFO nos sistemas BSD (incluindo OSX) e USR1 no Linux. No seu caso:

kill -INFO $PID

Você pode encontrar o ID do processo ( $PID acima) com o comando ps ; ou veja alternativas pgrep e pkill no mac os x para métodos mais convenientes.

Mais simplesmente, como AntoineG aponta em sua resposta , você pode digitar ctrl-T no shell executando dd para enviar o sinal INFO .

Como exemplo no Linux, você pode tornar todos os status% output dd ativos como este:

pkill -USR1 -x dd

Após exibir seu status, dd continuará copiando.

    
por 13.04.2011 / 19:23
96

No OS X (não tente no Linux), você pode simplesmente digitar Ctrl + T no terminal rodando 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)

Eu descobri sobre ele lendo este tópico, e tentando abrir uma nova aba no meu terminal mas misturando + T com Ctrl + T .

    
por 21.12.2012 / 07:48
26

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

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

Se você planeja com antecedência, envie os dados por meio de pv .

    
por 13.04.2011 / 20:54
16

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

EDIT: iotop -o mostra apenas programas que executam atualmente operações de I / O (obrigado Jason C para este comentário).

    
por 21.12.2012 / 12:09
13

Eu geralmente atribuo strace a esse processo em execução (com a opção -p $PID ) para ver se ele permanece bloqueado em uma chamada do sistema ou se ainda está ativo.

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

    
por 14.04.2011 / 09:26
11

Para a próxima vez, você pode usar apenas pv desde o início (se estiver disponível no gerenciador de pacotes, instale-o). Este é um utilitário com o único propósito de direcionar 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 através de dd , se você quiser), isso mostrará uma barra de progresso, velocidade média, velocidade atual e ETA.

A opção iflag=fullblock força o dd a pegar blocos inteiros de entrada através de pv , caso contrário você está à mercê do pipe para tamanhos de blocos.

Para ir por outro caminho use dd para ler e pv para escrever, embora você tenha que especificar explicitamente o tamanho se a origem 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 a ordem que você faz dd e pv in, é totalmente relacionado ao desempenho - se o dispositivo que você está lendo ou de tiver desempenho ideal para determinados blocksizes que você deseja usar dd em vez de pv para acessar esse dispositivo. Você pode até colocar um dd em ambas as extremidades, se quiser, ou não, se não se importar:

pv -ptearb /path/to/image.bin > /dev/whatever
sync
    
por 04.06.2014 / 21:45
8

A partir de coreutils v8.24, dd tem 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

    
por 11.01.2016 / 08:07
5

ddrescue fornecerá estatísticas durante a execução.

demo: link

    
por 14.04.2011 / 02:37
4

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

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

    iostat -d -w30 ada0

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

  2. Use ps para determinar quanto tempo dd está sendo executado:

    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 MB transferido total.
  4. Obtenha o tamanho do dispositivo em MB com:

    grep ada0 /var/run/dmesg.boot

    Substitua o nome do seu dispositivo de destino por 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é o momento para ter tempo restante.

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

    
por 08.12.2013 / 02:35
4

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

    
por 21.11.2014 / 09:20
2

Enquanto dd está em execução, eu executo isso em outro terminal como root:

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

Ele imprime o status dd a cada 1 segundo na janela do terminal original , onde dd está sendo executado, e sai quando o comando é concluído.

    
por 05.12.2015 / 18:40
2

Você pode usar progress , que, em particular, mostra o progresso de um dd em execução. Ele usa /proc/$pid/fd e /proc/$pid/fdinfo , que você também pode monitorar manualmente.

    
por 02.03.2017 / 13:00
1

A linha wchar (caracteres escritos) em /proc/$pid/io pode fornecer informações precisas sobre o processo dd . Contanto que mude, seu dd ainda está funcionando!

Aqui está um pequeno script php, que você pode salvar e executar com php filename.php durante o dd para exibir os bytes gravados. O bom benefício de assistir /proc/$pid/io over kill -USR1 $(pidof dd) é que você não precisa alternar entre 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";
}
    
por 28.10.2014 / 01:06