ฉันจะรู้ได้อย่างไรว่า dd ยังทำงานอยู่หรือไม่


147

ฉันไม่ได้ใช้ddทุกอย่างมาก แต่จนถึงตอนนี้มันยังไม่ได้ล้มเหลว ตอนนี้ฉันต้องใช้ddเวลานานกว่า 12 ชั่วโมง - ฉันกำลังเขียนรูปภาพกลับไปที่ดิสก์ที่มาจาก - และฉันเริ่มกังวลเล็กน้อยเนื่องจากฉันสามารถddถ่ายภาพจากดิสก์ไปยังภาพได้ในเวลาประมาณ 7 ชั่วโมง

ฉันใช้ OSX 10.6.6 บน MacBook กับ Core 2 Duo ที่ 2.1 กิกะเฮิร์ตซ์ / core พร้อม RAM ขนาด 4GB ฉันกำลังอ่านจาก. dmg บนฮาร์ดไดรฟ์ขนาด 7200rpm (ไดรฟ์สำหรับบูต) และฉันกำลังเขียนไปยังไดรฟ์ 7200rpm ที่เชื่อมต่อผ่านตัวเชื่อมต่อ SATA-to-USB ฉันปล่อยให้ขนาดบล็อกเป็นค่าเริ่มต้นและภาพประมาณ 160GB

แก้ไข: และหลังจาก 14 ชั่วโมงของความเครียดที่บริสุทธิ์ddทำงานได้อย่างสมบูรณ์แบบหลังจากทั้งหมด ครั้งต่อไปแม้ว่าฉันจะเรียกใช้ผ่านและติดตามด้วยpv straceขอบคุณทุกคนสำหรับความช่วยเหลือของคุณ


7
ไม่ตอบคำถามของคุณ แต่เวลาของคุณค่อนข้างสูง IMO คุณจำได้หรือไม่ว่าจะส่งผ่านขนาดบล็อกที่ใหญ่กว่าไปยังววที่ไม่ใช่ 512 ไบต์ดีฟอลต์? dd ... bs=16Mเป็นข้อเสนอแนะของฉันให้ RAM ขนาดดิสก์และความเร็วของคุณ
Juliano

ฉันไม่ได้เพราะฉันต้องการเล่นอย่างปลอดภัย ฉันจะลองในครั้งต่อไปแม้ว่า ขอบคุณ
eckza

จากประสบการณ์ของฉันddบน Mac OS X มีแนวโน้มที่จะหยุดนิ่งจนถึงจุดที่ฉันไม่สามารถแม้แต่จะฆ่ากระบวนการ แต่ต้องรีสตาร์ทระบบ ฉันใช้วิธีการทำงานบน Linux VM แล้ว
ssc

คำตอบ:


173

คุณสามารถส่งddสัญญาณบางอย่างโดยใช้killคำสั่งเพื่อให้มันส่งออกสถานะปัจจุบัน สัญญาณอยู่INFOในระบบ BSD (รวมถึง OSX) และUSR1บน Linux ในกรณีของคุณ:

kill -INFO $PID

คุณสามารถค้นหา id กระบวนการ ( $PIDด้านบน) ด้วยpsคำสั่ง; หรือดูทางเลือก pgrep และ pkill บน mac os xสำหรับวิธีที่สะดวกกว่า

ง่ายขึ้นเมื่อAntoineGชี้ให้เห็นในคำตอบของเขาคุณสามารถพิมพ์ctrl-Tที่ shell ที่ทำงาน dd เพื่อส่งINFOสัญญาณ

เป็นตัวอย่างบน Linux คุณสามารถสร้างddสถานะเอาต์พุตกระบวนการที่แอ็คทีฟทั้งหมดดังนี้:

pkill -USR1 -x dd

หลังจากแสดงสถานะแล้วddจะจัดการปัญหาต่อไป


9
โอ้เยี่ยมมาก คุณสามารถรวมสิ่งเหล่านั้นกับpkill -USR1 -x dd
Michael Mrozek

9
@kivetros: สำหรับระบบ BSD คุณต้องส่งINFOสัญญาณ Linux ไม่มี SIGINFO และใช้USR1แทน
Gilles

5
สัญญาณ SIGUSRx สำหรับโปรแกรมที่จะทำสิ่งที่พวกเขาต้องการเมื่อเทียบกับการมีความหมายมาตรฐาน ตัวอย่างเช่น SIGWINCH ถูกยกขึ้นเมื่อเทอร์มินัลเปลี่ยนขนาดและโปรแกรมอาจจำเป็นต้องวาดหน้าจอใหม่ ระบบปฏิบัติการไม่ได้ส่ง SIGUSRx เพื่อให้สามารถใช้งานได้เอง
LawrenceC

11
การส่งสัญญาณ USR1 ในไม่ช้าหลังจากที่เริ่มต้นขึ้นแล้ว (เช่นในสคริปต์ทุบตีบรรทัดหลังจากที่คุณเริ่มต้น) จะเป็นการยกเลิกสัญญาณ ใส่ 0.1 วินาทีในระหว่างนั้นและมันจะออกความคืบหน้าอย่างถูกต้อง โดยวิธีการที่คำสั่ง DD ที่ดีมากในการทดสอบ USR1 / INFO dd if=/dev/zero of=/dev/nullบนคือ :)
Lauritz V. Thaulow

11
BTW, BSD "จริง" ทั้งหมดส่ง SIGINFO ไปยังกลุ่มกระบวนการเบื้องหน้าหากอักขระสถานะ (Ctrl + T เป็นค่าเริ่มต้น) จะถูกส่งไปยังเทอร์มินัล แต่ฉันไม่รู้ว่าจริงหรือเปล่าสำหรับ MacOSX
Netch

100

ภายใต้ 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)

ผมพบว่าข้อมูลเกี่ยวกับมันอ่านกระทู้นี้และพยายามที่จะเปิดแท็บใหม่ใน terminal ของฉัน แต่ผสม+ Tกับ+CtrlT


1
โอ้ใช่แล้วloadการใช้งาน CPU เป็นอย่างไร
pje

นี่เป็นทางออกที่ดีกว่ามาก!
Stephn_R

ฉันลองใน dd บน Linux มันแค่สะท้อน^Tไปยังเทอร์มินัล
mwfearnley

1
ตรวจสอบให้แน่ใจว่าคุณกำลังทำ ctrl + shift + T ใน mac terminal
JBaczuk

26

สำหรับddคุณสามารถส่งสัญญาณ สำหรับคำสั่งอื่น ๆ ที่กำลังอ่านหรือเขียนไปยังไฟล์คุณสามารถดูตำแหน่งของพวกเขาในไฟล์lsofได้

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

pvถ้าคุณวางแผนล่วงหน้าท่อข้อมูลผ่าน


1
pv ดูน่าทึ่ง - ฉันจะใช้ครั้งต่อไปแน่นอน ขอบคุณมาก.
eckza

1
+1 - pvดูเหมือนกับตั๋ว
boehj

17

วิธีทั่วไปมากขึ้นคือการใช้iotopที่แสดงจำนวนปัจจุบันของการอ่าน / เขียนดิสก์ต่อโปรแกรม

แก้ไข: iotop -oแสดงเฉพาะโปรแกรมที่ดำเนินการ I / O ปัจจุบัน (ขอบคุณJason Cสำหรับความคิดเห็นนี้)


1
นี่เป็นวิธีตรวจสอบด่วนที่ฉันต้องการเช่นกัน iotop -oจะซ่อนกระบวนการที่ไม่ได้ทำ IO และทำให้ง่ายต่อการบอกทันทีว่าเกิดอะไรขึ้น
Jason C

13

ฉันมักจะแนบstraceไปกับกระบวนการทำงาน (พร้อม-p $PIDตัวเลือก) เพื่อดูว่ามันยังคงถูกบล็อกในการโทรของระบบหรือว่ายังคงใช้งานอยู่

หรือถ้าคุณรู้สึกประหม่าเกี่ยวกับการส่งสัญญาณไปยัง dd ที่กำลังทำงานให้เริ่มการทำงานของ dd อีกครั้งเพื่อตรวจสอบความถูกต้องหากใช้งานได้


2
คุณจะไปเกี่ยวกับการแนบstraceอย่างไร นอกจากนี้ฉันเริ่มต้นใหม่ddแล้วส่งสัญญาณที่แนะนำอย่างใดอย่างหนึ่งไปให้และ ... มันฆ่ามัน
eckza

2
หากคุณรู้ว่า pid ของกระบวนการ dd ที่กำลังทำงานอยู่ให้ทำ strace -p <pid> คุณควรจะเห็นบันทึกของระบบทุกสายที่เรียกว่าโดยกระบวนการ (ส่วนใหญ่อ่านและเขียน)
philfr

11

ในครั้งต่อไปคุณสามารถใช้งานได้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

จริงๆมันไม่สำคัญว่าสิ่งที่คุณทำเพื่อddและpvในก็ทั้งหมดที่เกี่ยวข้องกับประสิทธิภาพ - ถ้าอุปกรณ์ที่คุณกำลังอ่านไปยังหรือจากมีประสิทธิภาพการทำงานที่ดีที่สุดสำหรับการ blocksizes บางอย่างที่คุณต้องการที่จะใช้ddแทนpvในการเข้าถึงอุปกรณ์ที่ คุณสามารถติดddปลายทั้งสองข้างได้หากต้องการหรือไม่ทำเลยถ้าคุณไม่สนใจ:

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

10

ในฐานะของcoreutilsv8.24 ddมีการสนับสนุนพื้นเมืองสำหรับการแสดงความคืบหน้า status=progressเพียงแค่เพิ่มตัวเลือก

ตัวอย่าง:

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

แหล่ง



4

บางครั้งคุณอาจไม่สามารถใช้สัญญาณ INFO หรือ USR1 เนื่องจากกระแส stderr ของddกระบวนการไม่สามารถเข้าถึงได้ (เช่นเพราะเทอร์มินัลที่ถูกดำเนินการถูกปิดแล้ว) ในกรณีนี้การแก้ปัญหาคือทำสิ่งต่อไปนี้ (ทดสอบบน 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) ก็อาจลดอัตราการถ่ายโอน



2

ขณะที่ddกำลังดำเนินการอยู่ฉันรันสิ่งนี้ในเทอร์มินัลอื่นในฐานะรูท:

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

มันพิมพ์ddสถานะทุก 1 วินาทีในหน้าต่างเทอร์มินัลต้นฉบับที่ddกำลังดำเนินการและออกจากเมื่อคำสั่งเสร็จสิ้น


เจ๋ง. ทำงานได้ดีที่นี่ภายใต้ El Capitan
Stefano Mtangoo

2

คุณสามารถใช้progressความคืบหน้าของการวิ่งddได้โดยเฉพาะ มันใช้/proc/$pid/fdและ/proc/$pid/fdinfo คุณยังสามารถตรวจสอบด้วยมือ


1

wcharสาย (ตัวอักษรที่เขียน) ใน/proc/$pid/ioสามารถให้ข้อมูลที่ถูกต้องเกี่ยวกับddกระบวนการ ตราบใดที่มีการเปลี่ยนแปลงคุณddก็ยังทำงานอยู่!

นี่คือสคริปต์ php เล็กน้อยที่เรียบร้อยซึ่งคุณสามารถบันทึกและดำเนินการด้วยphp filename.phpในระหว่างddเพื่อแสดงไบต์ที่เขียน ประโยชน์ที่ดีของการดู/proc/$pid/ioมากกว่าkill -USR1 $(pidof dd)คือการที่คุณไม่จำเป็นต้องสลับไปมาระหว่างขั้วซึ่งไม่ได้เป็นตัวเลือกเสมอ

<?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";
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.