NFS Read/Write Histogram Calculation

This example shows a simple shellscript that uses tethereal to calculate NFS Read/Write I/O completion time histograms. It supports both version 2 and version 3 of NFS.

The script will output the number of NFS calls that completed within each of the 5 ms intervals starting at 0 to 100ms and one last datapoint for all calls that took more than 100ms to complete.
One such table will be printed for RREAD and one for WRITE.

Note that the -z rpc,rtt,... feature will only calculate the statistics based on those calls where both the REQUEST and the matching REPLY is in the capture file. REPLY packets with no matching REQUEST packet will be ignored.
Also note that if there are retransmission of REPLY packets, each REPLY packet will be considered unique and all of them will be used for the calculation.


Example output:

READ
5
7
8
...
2

WRITE
...



This tells us that 5 NFS READ commands completed within 0-5ms,
7 READs completed within 5-10ms, etc
and that 2 READs took >100ms to complete.

Similar for WRITEs.

#!/bin/sh


if [ $# != "2" ]; then
	echo "Usage: nfsrwhist.sh VERSION FILENAME"
	echo "   create read/write execution time for NFS version VERSION"
	echo
	echo "Example: nfsrwhist.sh 3 capture.cap"
	exit
fi

# -R "not frame" is a trick to prevent tethereal for printing any
# packet summary lines.  "not frame" is a read filter which will match
# no packets at all and thus tethereal will not print any packet summaries.
#
# the -z io,... statistics calculations still works though since it use
# its own packet filtering and ignores the read-filter.
tethereal -R "not frame" -r $2 \
-z "rpc,rtt,100003,$1,rpc.time>0.100" \
-z "rpc,rtt,100003,$1,rpc.time>0.095 && rpc.time<=0.100" \
-z "rpc,rtt,100003,$1,rpc.time>0.090 && rpc.time<=0.095" \
-z "rpc,rtt,100003,$1,rpc.time>0.085 && rpc.time<=0.090" \
-z "rpc,rtt,100003,$1,rpc.time>0.080 && rpc.time<=0.085" \
-z "rpc,rtt,100003,$1,rpc.time>0.075 && rpc.time<=0.080" \
-z "rpc,rtt,100003,$1,rpc.time>0.070 && rpc.time<=0.075" \
-z "rpc,rtt,100003,$1,rpc.time>0.065 && rpc.time<=0.070" \
-z "rpc,rtt,100003,$1,rpc.time>0.060 && rpc.time<=0.065" \
-z "rpc,rtt,100003,$1,rpc.time>0.055 && rpc.time<=0.060" \
-z "rpc,rtt,100003,$1,rpc.time>0.050 && rpc.time<=0.055" \
-z "rpc,rtt,100003,$1,rpc.time>0.045 && rpc.time<=0.050" \
-z "rpc,rtt,100003,$1,rpc.time>0.040 && rpc.time<=0.045" \
-z "rpc,rtt,100003,$1,rpc.time>0.035 && rpc.time<=0.040" \
-z "rpc,rtt,100003,$1,rpc.time>0.030 && rpc.time<=0.035" \
-z "rpc,rtt,100003,$1,rpc.time>0.025 && rpc.time<=0.030" \
-z "rpc,rtt,100003,$1,rpc.time>0.020 && rpc.time<=0.025" \
-z "rpc,rtt,100003,$1,rpc.time>0.015 && rpc.time<=0.020" \
-z "rpc,rtt,100003,$1,rpc.time>0.010 && rpc.time<=0.015" \
-z "rpc,rtt,100003,$1,rpc.time>0.005 && rpc.time<=0.010" \
-z "rpc,rtt,100003,$1,rpc.time<=0.005" >/tmp/nfsrwhist.$$

echo -n "READ: "
cat /tmp/nfsrwhist.$$ | grep "^READ " | sed -e "s/^READ *//g" -e "s/ .*$//"
echo

echo -n "WRITE: "
cat /tmp/nfsrwhist.$$ | grep "^WRITE " | sed -e "s/^WRITE *//g" -e "s/ .*$//"
echo

rm /tmp/nfsrwhist.$$