मैं आपकी पर्ल स्क्रिप्ट को सिस्टम कॉल ट्रेस टूल: 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
...