Làm thế nào tôi có thể biết nếu bộ đệm ống đã đầy?


11

Tôi đang đầu ra đường ống từ một chương trình vào một số Perl tôi đã viết. Đây là một quá trình dài, đôi khi nhiều ngày, vì vậy tôi muốn tìm ra nơi tắc nghẽn của tôi và cố gắng mở chúng ra. Tôi muốn biết liệu dữ liệu được chuyển vào tập lệnh của tôi nhanh hơn tập lệnh của tôi có thể xử lý nó hay không. Nếu đây là trường hợp tôi sẽ cố gắng điều chỉnh kịch bản của mình, nhưng không phải nếu tôi không cần. Tôi thấy nói về một cờ được đặt khi bộ đệm đầy, ngăn không cho ghi thêm vào nó nhưng làm cách nào để kiểm tra xem cờ đó có được đặt thường xuyên không? Có ý kiến ​​gì không?


3
Tôi nghĩ rằng chỉ có quá trình viết có thể biết.
enzotib

5
Bạn có thể xem xét sử dụng pvmột nơi nào đó dọc theo chuỗi ống.
amphetamachine

Câu trả lời:


9

Tôi sẽ theo dõi tập lệnh Perl của bạn bằng công cụ theo dõi cuộc gọi hệ thống: strace(Linux), dtruss(OS X), ktrace(FreeBSD), truss(Solaris), v.v. Mục tiêu sẽ là xem tập lệnh Perl của bạn dành bao nhiêu thời gian để đọc từ nó stdin và chương trình kia dành bao nhiêu thời gian chờ đợi để viết lên thiết bị xuất chuẩn của nó.

Ở đây tôi đang thử nghiệm điều này với người viết là nút cổ chai:

terminal 1$ gzip -c < /dev/urandom | cat > /dev/null

terminal 2$ ps auxw | egrep 'gzip|cat'
slamb    25311 96.0  0.0  2852  516 pts/0    R+   23:35   3:40 gzip -c
slamb    25312  0.8  0.0  2624  336 pts/0    S+   23:35   0:01 cat

terminal 2$ strace -p 25312 -s 0 -rT -e trace=read
Process 25312 attached - interrupt to quit
     0.000000 read(0, ""..., 4096) = 4096 <0.005207>
     0.005531 read(0, ""..., 4096) = 4096 <0.000051>

Số đầu tiên ở đây là thời gian kể từ khi bắt đầu tòa nhà trước đó và số cuối cùng là thời gian dành cho tòa nhà. Vì vậy, chúng tôi có thể xử lý hậu kỳ với Perl một chút để tổng hợp nó ... [*]

terminal 2$ strace -p 25312 -s 0 -rT -e trace=read 2>&1 | perl -nle 'm{^\s*([\d.]+) read\(0, .*<([\d.]+)>} or next; $total_work += $1 - $last_wait; $total_wait += $2; $last_wait = $2; print "working for $total_work sec, waiting for $total_wait sec"; $last_wait = $2;'
working for 0 sec, waiting for 0.005592 sec
...
working for 0.305356 sec, waiting for 2.28624900000002 sec
...

terminal 2$ strace -p 25311 -s 0 -rT -e trace=write 2>&1 | perl -nle 'm{^\s*([\d.]+) write\(1, .*<([\d.]+)>} or next; $total_work += $1 - $last_wait; $total_wait += $2; $last_wait = $2; print "working for $total_work sec, waiting for $total_wait sec"; $last_wait = $2;'
...
working for 5.15862000000001 sec, waiting for 0.0555740000000007 sec
...

Bạn có thể truy cập fancier và tạo tập lệnh SystemTap hoặc DTrace, theo dõi cả hai mặt cùng một lúc, chỉ theo dõi bộ mô tả tệp chính xác và in cập nhật trạng thái đẹp mỗi giây hoặc lâu hơn với mỗi phần trăm thời gian đang chờ cho bên kia.

[*] - Cảnh báo: tập hợp thô của tôi không hoàn toàn đúng nếu đọc / ghi được gọi trên các mô tả tệp khác; nó sẽ đánh giá thấp thời gian làm việc trong trường hợp đó.


Phiên bản dtrace thực sự khá gọn gàng.

terminal 1$ gzip -c < /dev/urandom | cat > /dev/null

terminal 2$ ps aux | egrep 'gzip| cat'
slamb    54189  95.8  0.0   591796    584 s006  R+   12:49AM  22:49.55 gzip -c
slamb    54190   0.4  0.0   599828    392 s006  S+   12:49AM   0:06.08 cat

terminal 2$ cat > pipe.d <<'EOF'
#!/usr/sbin/dtrace -qs

BEGIN
{
  start = timestamp;
  writer_blocked = 0;
  reader_blocked = 0;
}

tick-1s, END
{
  this->elapsed = timestamp - start;
  printf("since startup, writer blocked %3d%% of time, reader %3d%% of time\n",
         100 * writer_blocked / this->elapsed,
         100 * reader_blocked / this->elapsed);
}

syscall::write:entry
/pid == $1 && arg0 == 1/
{
  self->entry = timestamp;
}

syscall::write:return
/pid == $1 && self->entry != 0/
{
  writer_blocked += timestamp - self->entry;
  self->entry = 0;
}

syscall::read:entry
/pid == $2 && arg0 == 0/
{
  self->entry = timestamp;
}

syscall::read:return
/pid == $2 && self->entry != 0/
{
  reader_blocked += timestamp - self->entry;
  self->entry = 0;
}
EOF

terminal 2$ chmod u+x pipe.d
terminal 2$ sudo ./pipe.d 54189 54190
since startup, writer blocked   0% of time, reader  98% of time
since startup, writer blocked   0% of time, reader  99% of time
since startup, writer blocked   0% of time, reader  99% of time
since startup, writer blocked   0% of time, reader  99% of time
since startup, writer blocked   0% of time, reader  99% of time
^C
since startup, writer blocked   0% of time, reader  99% of time

Và phiên bản SystemTap:

terminal 1$ gzip -c /dev/urandom | cat > /dev/null

terminal 2$ ps auxw | egrep 'gzip| cat'
slamb     3405  109  0.0   4356   584 pts/1    R+   02:57   0:04 gzip -c /dev/urandom
slamb     3406  0.2  0.0  10848   588 pts/1    S+   02:57   0:00 cat

terminal 2$ cat > probes.stp <<'EOF'
#!/usr/bin/env stap

global start
global writer_pid
global writes
global reader_pid
global reads

probe begin {
  start = gettimeofday_us()
  writer_pid = strtol(argv[1], 10)
  reader_pid = strtol(argv[2], 10)
}

probe timer.s(1), end {
  elapsed = gettimeofday_us() - start
  printf("since startup, writer blocked %3d%% of time, reader %3d%% of time\n",
         100 * @sum(writes) / elapsed,
         100 * @sum(reads) / elapsed)
}

probe syscall.write.return {
  if (pid() == writer_pid && $fd == 1)
    writes <<< gettimeofday_us() - @entry(gettimeofday_us())
}

probe syscall.read.return {
  if (pid() == reader_pid && $fd == 0)
    reads <<< gettimeofday_us() - @entry(gettimeofday_us())
}
EOF

terminal 2$ chmod a+x probes.stp
terminal 2$ sudo ./pipe.stp 3405 3406
since startup, writer blocked   0% of time, reader  99% of time
...

6

Bạn có thể chèn một pv -TClệnh trong đường ống của bạn:

cmd1 | pv -TC | cmd2

pvsử dụng bộ đệm riêng của nó và -Tlàm cho nó báo cáo mức độ trung bình của nó trong khoảng thời gian 1 giây (theo mặc định).

Nếu nó luôn luôn là 100%, thì điều đó có nghĩa cmd1là sản xuất đầu ra nhanh hơn so cmd2với việc tiêu thụ nó. Nếu không, thì đó là cách khác. Coi chừng đường ống có thể chứa 64kB.

Xem thêm -Bđể chỉ định pvkích thước bộ đệm. Bạn có thể sử dụng một vài pvs như trong:

$ cmd1 | pv -cCTrbN 'cmd1 -> cmd2' | cmd2 | pv -cCTrbN 'cmd2 -> cmd3' | cmd3
cmd1 -> cmd2: 1.92GiB { 53%} [ 387MiB/s]
cmd2 -> cmd3: 1.92GiB {  0%} [ 387MiB/s]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.