2011-02-22

ネットワークの伝送効率と遅延を ping を用いて測定する

localhost とある host との間の伝送効率と遅延を ping を用いて測定した.ping を使うアイデアは,pingでネットワークの速度を調査する - @IT にて示されている.以下の bash プログラムでは,大きさの異なるパケットを指定された host に対して ping し,往復にかかった時間を測る.これらパケットサイズと往復にかかった時間との関係に一次関数を仮定し,フィッティングして得た傾きと切片をそれぞれ伝送効率と遅延とする.最小二乗フィッティングには gnuplot を使った.その後一定時間の休みを挟み,測定を繰り返す.各繰り返しでは,その繰り返しで測定した結果だけではなく,それまでに測定した結果をすべてフィッティング対象にする.

#!/bin/bash

readonly counts=1
readonly maxsize=1472
readonly sleepsecond=600

remote="${1}"
shift
if [ "x${remote}" = 'x' ]; then
    echo "Usage: ${0} remote_host" >&2
    exit 1
fi

resultfile=$( mktemp )
trap "rm -r ${resultfile}" EXIT

countsprev=0
for (( i=1;; i++ ))
do
    s=${maxsize}
    while true
    do
        if [ ! ${s} -gt 0 ]; then
            break
        fi

        unset pattern
        while [ "x${pattern}" = 'x' ]
        do
            pattern=$(hexdump -e '/2 "%02x"' -n "${s}" /dev/urandom)
        done
        
        ping -c "${counts}" -p "${pattern}" -s "${s}" "${remote}" \
            | awk '$2 == "bytes" && $3 == "from" && $4 = "'"${remote}"':" { print $1, $7 }' \
            | while read size time
        do
            if [ "x${size}" = 'x' ]; then
                continue
            fi
            if [ "x${time}" = 'x' ]; then
                exit 128
            fi
            time_ms="${time#time=}"
            echo "${size} ${time_ms}" >> "${resultfile}"
        done
        if [ $? -eq 128 ]; then
            break
        fi
        if [ $? -ne 0 ]; then
            echo "Failed: ping -c ${counts} -p ${pattern} -s ${s} ${remote}" >&2
        fi

        s=$( echo "scale=0; ${s}/1.41421356" | bc )
    done

    echo "data [${i}]:"
    tail -$( expr $( wc -l < "${resultfile}" ) - ${countsprev} ) ${resultfile}
    countsprev=$( wc -l < "${resultfile}" )
    echo "data [${i}] end: ${countsprev}"

    gnuplot -persist <(echo \
"fit a*x+b '${resultfile}' using 1:2 via a, b
print \"transport rate: \", 1000/a/1024/1024*2, \" Mbytes/s\"
print \"      overhead: \", b, \" ms\"
plot a*x+b, '${resultfile}' using 1:2") 2>&1 \
    | sed -n '/^After [1-9][0-9]* iterations the fit converged\. *$/,$ p'

    sleep "${sleepsecond}"
done