मैं कैसे बता सकता हूं कि क्या पाइप बफर भरा हुआ है?


11

मैं एक प्रोग्राम से कुछ पर्ल में लिखी गई आउटपुट को पाइप कर रहा हूं। यह एक लंबी चलने वाली प्रक्रिया है, कभी-कभी दिन, इसलिए मैं यह पता लगाना चाहता हूं कि मेरी अड़चनें कहां हैं और उन्हें खोलने की कोशिश करें। मैं जानना चाहता हूं कि क्या मेरी स्क्रिप्ट से डेटा तेजी से मेरी स्क्रिप्ट में डाला जा रहा है या नहीं। अगर ऐसा है तो मैं अपनी स्क्रिप्ट को ट्यून करने की कोशिश करूँगा, लेकिन अगर मुझे ज़रूरत नहीं है तो नहीं। मैं एक ध्वज के सेट के बारे में बात करता हूं जब बफर भरा हुआ होता है जो इसे और अधिक लिखने से रोकता है लेकिन मैं यह देखने के लिए कैसे जांचता हूं कि क्या या कितनी बार उस ध्वज को सेट किया गया है? कोई विचार?


3
मुझे लगता है कि केवल लेखन प्रक्रिया ही जान सकती थी।
enzotib

5
आप pvपाइप श्रृंखला के साथ कहीं का उपयोग कर सकते हैं ।
एम्फेटामैचिन

जवाबों:


9

मैं आपकी पर्ल स्क्रिप्ट को सिस्टम कॉल ट्रेस टूल: strace(लिनक्स), dtruss(ओएस एक्स), ktrace(फ्रीबीएसडी), truss(सोलारिस), आदि के साथ ट्रेस करूंगा। लक्ष्य यह होगा कि आपकी पर्ल स्क्रिप्ट को पढ़ने से लेकर उसके इंतजार में कितना समय मिले। स्टडिन और कितना समय अन्य कार्यक्रम अपने स्टडआउट को लिखने पर इंतजार करता है।

यहाँ मैं इसे लेखक के साथ अड़चन के रूप में परख रहा हूँ:

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>

यहां पहला नंबर पिछले syscall की शुरुआत के बाद का समय है, और आखिरी नंबर syscall में बिताया गया समय है। इसलिए हम पर्ल के साथ इसे एग्रीगेट करने के लिए थोड़ा प्रोसेस कर सकते हैं ... [*]

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
...

आप कट्टर जा सकते हैं और एक SystemTap या DTrace स्क्रिप्ट बना सकते हैं जो एक ही बार में दोनों पक्षों का पता लगाता है, केवल सही फ़ाइल डिस्क्रिप्टर को ट्रैक करता है, और हर दूसरे या इतने प्रतिशत के साथ एक अच्छा स्टेटस अपडेट प्रिंट करता है कि प्रत्येक दूसरे के लिए कितने प्रतिशत इंतजार कर रहा था।

[*] - चेतावनी: पढ़ने / लिखने को अन्य फाइल डिस्क्रिप्टर पर बुलाया जा रहा है तो मेरा क्रूड एग्रीगेशन बिल्कुल सही नहीं है; यह उस मामले में काम के समय को कम करेगा।


Dtrace संस्करण वास्तव में बहुत साफ है।

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

और 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

आप pv -TCअपनी पाइप लाइन में कमांड डाल सकते हैं :

cmd1 | pv -TC | cmd2

pvअपने स्वयं के बफर का उपयोग करता है और -Tयह रिपोर्ट करता है कि यह 1 सेकंड की अवधि (डिफ़ॉल्ट रूप से) पर औसत रूप से कितना भरा हुआ है।

यदि यह हमेशा 100% है, तो इसका मतलब cmd1है कि इसका उत्पादन करने की तुलना cmd2में उत्पादन में तेजी है। यदि नहीं, तो यह दूसरा तरीका है। खबरदार कि पाइप खुद 64kB पकड़ सकते हैं।

बफ़र का आकार -Bनिर्दिष्ट करने के लिए भी देखें pv। आप में से कई का उपयोग कर सकते हैं pv:

$ 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]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.