it-swarm-vi.com

Làm sao để biết dd vẫn hoạt động?

Tôi đã không sử dụng dd rất nhiều, nhưng cho đến nay nó vẫn chưa làm tôi thất bại. Ngay bây giờ, tôi đã có dd kéo dài hơn 12 giờ - Tôi đang viết một hình ảnh trở lại đĩa mà nó xuất phát - và tôi cảm thấy hơi lo lắng, vì tôi đã có thể dd từ đĩa vào hình ảnh trong khoảng 7 giờ.

Tôi đang chạy OSX 10.6.6 trên MacBook với Core 2 Duo với tốc độ 2.1ghz/lõi với RAM 4gb. Tôi đang đọc từ .dmg trên ổ cứng 7200rpm (ổ đĩa khởi động) và tôi đang ghi vào ổ 7200rpm được kết nối qua đầu nối SATA-USB. Tôi để mặc định kích thước khối và hình ảnh khoảng 160gb.

EDIT: Và, sau 14 giờ căng thẳng thuần túy, dd đã hoạt động hoàn hảo. Tuy nhiên, lần tới, tôi sẽ chạy nó qua pv và theo dõi nó bằng strace. Cảm ơn tất cả mọi người vì tất cả sự giúp đỡ của bạn.

150
eckza

Bạn có thể gửi dd một tín hiệu nhất định bằng cách sử dụng lệnh kill để làm cho nó xuất ra trạng thái hiện tại. Tín hiệu là INFO trên các hệ thống BSD (bao gồm cả OSX) và USR1 trên Linux. Trong trường hợp của bạn:

kill -INFO $PID

Bạn có thể tìm thấy id quá trình ($PID ở trên) với lệnh ps; hoặc xem pgrep và pkill thay thế trên mac os x để biết các phương pháp thuận tiện hơn.

Đơn giản hơn, như AntoineG chỉ ra trong câu trả lời của anh ấy , bạn có thể nhập ctrl-T tại Shell đang chạy dd để gửi tín hiệu INFO.

Như một ví dụ trên Linux, bạn có thể tạo tất cả dd đang xử lý trạng thái đầu ra như sau:

pkill -USR1 -x dd

Sau khi xuất trạng thái của nó, dd sẽ tiếp tục đối phó.

176
Caleb

Trong OS X (không thử trên Linux), bạn chỉ cần gõ Ctrl+T trong thiết bị đầu cuối đang chạy dd. Nó sẽ in cùng một đầu ra là kill -INFO $PID, cộng với việc sử dụng 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ôi phát hiện ra nó đang đọc chủ đề này và cố gắng mở một tab mới trong thiết bị đầu cuối của mình nhưng trộn +T với Ctrl+T.

104
AntoineG

Với dd, bạn có thể gửi tín hiệ . Đối với các lệnh khác đang đọc hoặc ghi vào tệp, bạn có thể xem vị trí của chúng trong tệp với lsof .

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

Nếu bạn có kế hoạch trước, hãy chuyển dữ liệu qua pv .

Một cách tổng quát hơn là sử dụng iotop hiển thị số lượng đọc/ghi đĩa hiện tại trên mỗi chương trình.

BIÊN TẬP: iotop -o chỉ hiển thị các chương trình thực hiện các thao tác I/O hiện tại (cảm ơn Jason C cho nhận xét này).

17
jofel

Tôi thường đính kèm strace vào một quy trình đang chạy như vậy (với -p $PID tùy chọn) để xem liệu nó có bị chặn trong một cuộc gọi hệ thống hay nếu nó vẫn còn hoạt động.

Hoặc, nếu bạn cảm thấy lo lắng về việc gửi tín hiệu đến dd đang chạy, hãy bắt đầu một dd khác để xác thực nếu điều này hoạt động.

13
philfr

Lần sau, bạn chỉ có thể sử dụng pv từ đầu (nếu có sẵn thông qua trình quản lý gói của bạn, hãy cài đặt nó). Đây là một tiện ích với mục đích duy nhất là đầu vào đường ống đến đầu ra và theo dõi tiến độ và tốc độ.

Sau đó, để ghi hình ảnh vào ổ đĩa, hãy nói với kích thước khối 4MB:

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

Ngoài bộ đệm ban đầu (được bù bởi đồng bộ hóa cuối cùng, có thể được thực hiện thông qua dd nếu bạn muốn), điều này sẽ hiển thị cho bạn một thanh tiến trình, tốc độ trung bình, tốc độ hiện tại và ETA.

Các iflag=fullblock tùy chọn buộc dd lấy toàn bộ khối đầu vào thông qua pv, nếu không, bạn sẽ phải chịu đựng các kích thước của đường ống.

Để đi theo cách khác, sử dụng dd để đọc và pv để viết, mặc dù bạn phải xác định rõ kích thước nếu nguồn là một thiết bị khối. Đối với thiết bị 4GB:

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

Bạn cũng có thể xác định kích thước tự động, đại loại như:

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

Thực sự không có vấn đề gì khi bạn thực hiện theo thứ tự ddpv in, nó hoàn toàn liên quan đến hiệu suất - nếu thiết bị bạn đang đọc hoặc từ đó có hiệu suất tối ưu cho một số khối nhất định bạn muốn sử dụng dd thay vì pv để truy cập thiết bị đó. Bạn thậm chí có thể dán dd ở cả hai đầu nếu bạn muốn hoặc hoàn toàn không nếu bạn không quan tâm:

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

Kể từ coreutils v8.24, dd có hỗ trợ riêng để hiển thị tiến trình. Chỉ cần thêm tùy chọn status=progress.

Thí dụ:

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

Nguồn

10

ddrescue sẽ cung cấp cho bạn số liệu thống kê khi nó đang chạy.

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

5
Ben Preston

Tôi bắt đầu sử dụng dcfldd (1), cho thấy các thao tác dd theo cách tốt hơn.

4
Kartik M

Đôi khi, bạn không thể sử dụng tín hiệu INFO hoặc USR1 vì luồng stderr của quá trình dd không truy cập được (ví dụ: vì thiết bị đầu cuối được thực thi đã bị đóng). Trong trường hợp này, một cách giải quyết là thực hiện các thao tác sau (được thử nghiệm trên FreeBSD, có thể hơi khác trên Linux):

  1. Sử dụng iostat để ước tính tốc độ ghi trung bình (MB/s) cho thiết bị đích, ví dụ:

    iostat -d -w30 ada0

    Thay thế tên thiết bị mục tiêu của bạn cho ada0 ở đây, và đợi một phút để nó đưa ra một vài kết quả. Tham số "w" xác định có bao nhiêu giây giữa các mẫu. Việc tăng nó sẽ cho ước tính trung bình tốt hơn với ít phương sai hơn, nhưng bạn sẽ phải chờ lâu hơn.

  2. Sử dụng ps để xác định thời gian dd đã chạy:

    ps -xo etime,command | grep dd

    Chuyển đổi này thành giây để có được tổng số giây thời gian chạy.

  3. Nhân tổng số giây thời gian chạy với tốc độ ghi trung bình để có tổng MB được chuyển.
  4. Lấy kích thước thiết bị tính bằng MB với:

    grep ada0 /var/run/dmesg.boot

    Thay thế tên thiết bị mục tiêu của bạn cho ada0. Chia kết quả cho tốc độ ghi trung bình để có tổng thời gian chuyển tính bằng giây. Trừ đi thời gian nó đã chạy cho đến nay để có thời gian còn lại.

Chiến lược này chỉ hoạt động nếu dd đã được viết liên tục ở tốc độ ghi trung bình hiện tại kể từ khi nó bắt đầu. Nếu các quá trình khác đang cạnh tranh cho tài nguyên CPU hoặc I/O (bao gồm cả bus I/O) thì nó có thể làm giảm tốc độ truyền.

4
D Coetzee

Bạn có thể sử dụng progress , cụ thể, hiển thị tiến trình của một dd đang chạy. Nó sử dụng /proc/$pid/fd/proc/$pid/fdinfo mà bạn cũng có thể theo dõi bằng tay.

3
jofel

Trong khi dd đang thực thi, tôi chạy cái này trong một thiết bị đầu cuối khác dưới dạng root:

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

Nó in trạng thái dd cứ sau 1 giây trong cửa sổ đầu cuối gốc trong đó dd đang thực thi và thoát khi lệnh được thực hiện.

2
ccpizza

Dòng wchar (ký tự viết) trong /proc/$pid/io Có thể cung cấp cho bạn thông tin chính xác về quy trình dd. Miễn là nó thay đổi, dd của bạn vẫn hoạt động!

Đây là một tập lệnh php nhỏ gọn, bạn có thể lưu và thực hiện với php filename.php Trong dd để hiển thị các byte được viết. Lợi ích tuyệt vời của việc xem /proc/$pid/io Trên kill -USR1 $(pidof dd) là bạn không phải chuyển đổi giữa các thiết bị đầu cuối, điều này không phải lúc nào cũng là một tùy chọ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";
}
1
Leon Kramer