it-swarm.cn

我怎么知道dd是否仍在工作?

我还没用过dd,但是到目前为止我还没有失败。现在,我有一个dd进行了12个小时以上-我正在将映像写回到它来自的磁盘中-我有点担心,因为我能够dd从磁盘到映像大约需要7个小时。

我在配备Core 2 Duo的MacBook上运行OSX 10.6.6,速度为2.1ghz/core,带有4GB RAM。我正在从7200rpm硬盘驱动器(引导驱动器)上的.dmg读取,并且正在写入通过SATA-USB连接器连接的7200rpm驱动器。默认情况下,我保留了块大小,图像约为160gb。

编辑:而且,经过14个小时的纯压力后,dd毕竟工作完美。不过,下一次,我将通过pv运行它,并使用strace对其进行跟踪。感谢大家的帮助。

150
eckza

您可以使用dd命令发送 kill 某个信号,以使其输出当前状态。在BSD系统(包括OSX)上,信号是INFO;在Linux上,信号是USR1。在您的情况下:

kill -INFO $PID

您可以使用ps命令找到进程ID(上面的$PID);或参阅 在Mac OS X上为pgrep和pkill替代 了解更方便的方法。

更简单地说,正如 AntoineG他的答案 中指出的那样,您可以在运行dd的Shell上键入ctrl-T来发送INFO信号。

例如,在Linux上,您可以使所有活动的dd进程输出状态如下:

pkill -USR1 -x dd

输出其状态后,dd将继续处理。

176
Caleb

在OS X(未在Linux上尝试)下,您只需输入 Ctrl+T 在运行dd的终端中。它将输出与kill -INFO $PID相同的输出,外加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)

我通过阅读此线程发现了这个问题,并尝试在终端中打开一个新标签页 +T 与 Ctrl+T

104
AntoineG

对于dd,您可以 发送信号 。对于正在读取或写入文件的其他命令,您可以使用 lsof 监视它们在文件中的位置。

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

如果您事先计划,请通过 pv 传递数据。

26

一种更通用的方法是使用 iotop 显示每个程序当前的磁盘读取/写入量。

编辑:iotop -o仅显示当前正在执行I/O操作的程序(对于此注释,感谢 (Jason C ))。

17
jofel

我通常将strace附加到这样一个正在运行的进程中(使用-p $PID选项),以查看它是否在系统调用中保持阻止状态或是否仍处于活动状态。

或者,如果您对将信号发送到正在运行的dd感到不安,请启动另一个dd以验证其是否有效。

13
philfr

对于下一次,您可以从一开始就使用pv(如果可以通过包管理器使用它,请安装它)。这是一个实用程序,其唯一目的是通过管道输入来输出并监视进度和速度。

然后,要将图像写入驱动器,例如以4MB的块大小:

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

除了初始缓冲(如果需要,可以通过dd进行最终同步补偿),这将向您显示进度条,平均速度,当前速度和ETA。

iflag=fullblock选项会强制dd通过pv来获取完整的输入块,否则,您将无法决定块大小。

如果源是块设备,则必须显式指定大小,但要使用另一种方法,请使用dd读取和pv写入。对于4GB设备:

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

您还可以自动确定尺寸,例如:

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

ddpv的执行顺序实际上并不重要,这完全与性能有关-如果您要读取或读取的设备对于某些块大小具有最佳性能,使用dd而非pv访问该设备。如果需要,您甚至可以在两端都贴上dd,如果您根本不在乎,则根本不使用:

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

coreutils v8.24起,dd具有显示进度的本机支持。只需添加选项status=progress

例:

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

来源

10
Chirag Bhatia - chirag64

ddrescue会在运行时为您提供统计信息。

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

5
Ben Preston

我开始使用dcfldd(1),它以更好的方式显示了dd操作。

4
Kartik M

有时您可能无法使用INFO或USR1信号,因为无法访问dd进程的stderr流(例如,由于执行该命令的终端已经关闭)。在这种情况下,一种解决方法是执行以下操作(在FreeBSD上进行测试,在Linux上可能略有不同):

  1. 使用iostat估计对目标设备的平均写入速率(MB/s),例如:

    iostat -d -w30 ada0

    用目标设备名称替换ada0在这里,请稍等片刻,以获得一些结果。 “ w”参数确定样本之间的间隔秒数。增加它可以得到更好的平均估计,并且方差较小,但是您必须等待更长的时间。

  2. 使用ps确定dd已运行多长时间:

    ps -xo etime,command | grep dd

    将其转换为秒数可获得运行时间的总秒数。

  3. 将运行时间的总秒数乘以平均写入速率即可得出总的已传输MB。
  4. 使用以下命令获取设备大小(MB):

    grep ada0 /var/run/dmesg.boot

    用目标设备名称替换ada0。将结果除以平均写入速率即可得到以秒为单位的总传输时间。减去到目前为止已运行的时间,以获取剩余时间。

此策略仅在自开始以来以dd一直以当前的平均写入速率连续写入时才有效。如果其他进程正在争夺CPU或I/O资源(包括I/O总线),则可能会降低传输速率。

4
D Coetzee

您可以使用 progress ,它特别显示正在运行的dd的进度。它用 /proc/$pid/fd/proc/$pid/fdinfo,您也可以手动监视。

3
jofel

在执行dd时,我以root身份在另一个终端中运行此命令:

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

它每1秒钟打印dd状态在原始终端窗口中执行dd的位置,并在命令完成后退出。

2
ccpizza

_/proc/$pid/io_中的wchar行(手写字符)可以为您提供有关dd进程的准确信息。只要更改,您的dd仍然可以使用!

这是一个简洁的PHP脚本,您可以保存该脚本,然后在dd期间使用_php filename.php_执行该脚本,以显示写入的字节。与_kill -USR1 $(pidof dd)相比,观看_/proc/$pid/io_的好处是您不必在终端之间进行切换,这并不总是一种选择。

_<?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";
}
_
1
Leon Kramer