diff --git a/betterspeedtest.sh b/betterspeedtest.sh index c35b4ac..90673f0 100755 --- a/betterspeedtest.sh +++ b/betterspeedtest.sh @@ -18,49 +18,11 @@ # -i | --idle: Don't send traffic, only measure idle latency # -n | --number: Number of simultaneous sessions (default - 5 sessions) -# Copyright (c) 2014-2019 - Rich Brown rich.brown@blueberryhillsoftware.com +# Copyright (c) 2014-2022 - Rich Brown rich.brown@blueberryhillsoftware.com # GPLv2 -# Summarize the contents of the ping's output file to show min, avg, median, max, etc. -# input parameter ($1) file contains the output of the ping command - -summarize_pings() { - - # Process the ping times, and summarize the results - # grep to keep lines that have "time=", then sed to isolate the time stamps, and sort them - # awk builds an array of those values, and prints first & last (which are min, max) - # and computes average. - # If the number of samples is >= 10, also computes median, and 10th and 90th percentile readings - - # stop pinging and drawing dots - kill_pings - kill_dots - - sed 's/^.*time=\([^ ]*\) ms/\1/' < "$1" | grep -v "PING" | sort -n | \ - awk 'BEGIN {numdrops=0; numrows=0;} \ - { \ - if ( $0 ~ /timeout/ ) { \ - numdrops += 1; \ - } else { \ - numrows += 1; \ - arr[numrows]=$1; sum+=$1; \ - } \ - } \ - END { \ - pc10="-"; pc90="-"; med="-"; \ - if (numrows == 0) {numrows=1} \ - if (numrows>=10) \ - { ix=int(numrows/10); pc10=arr[ix]; ix=int(numrows*9/10);pc90=arr[ix]; \ - if (numrows%2==1) med=arr[(numrows+1)/2]; else med=(arr[numrows/2]); \ - }; \ - pktloss = numdrops/(numdrops+numrows) * 100; \ - printf("\n Latency: (in msec, %d pings, %4.2f%% packet loss)\n Min: %4.3f \n 10pct: %4.3f \n Median: %4.3f \n Avg: %4.3f \n 90pct: %4.3f \n Max: %4.3f\n", numrows, pktloss, arr[1], pc10, med, sum/numrows, pc90, arr[numrows] )\ - }' - - # and finally remove the PINGFILE - rm "$1" - -} +# include the summarize_pings() function from the lib directory +. "./lib/summarize_pings.sh" # Print a line of dots as a progress indicator. @@ -89,12 +51,22 @@ kill_pings() { ping_pid=0 } + +# Clean up all the debris from the testing +clean_up() { + kill_pings + kill_dots + rm "$PINGFILE" +} + # Stop the current pings and dots, and exit # ping command catches (and handles) first Ctrl-C, so you have to hit it again... -kill_pings_and_dots_and_exit() { - kill_dots - kill_pings +catch_interrupt() { printf "\nStopped" + kill_pings + kill_dots + summarize_pings "$PINGFILE" + rm "$PINGFILE" exit 1 } @@ -169,7 +141,8 @@ measure_direction() { # When netperf completes, summarize the ping data summarize_pings "$PINGFILE" - rm "$SPEEDFILE" + # stop the dots & pings, rm "$PINGFILE" + clean_up } # ------- Start of the main routine -------- @@ -240,8 +213,8 @@ else fi DATE=$(date "+%Y-%m-%d %H:%M:%S") -# Catch a Ctl-C and stop the pinging and the print_dots -trap kill_pings_and_dots_and_exit HUP INT TERM +# Catch a Ctl-C and close up +trap catch_interrupt HUP INT TERM if $IDLETEST then @@ -249,6 +222,7 @@ then start_pings sleep "$TESTDUR" summarize_pings "$PINGFILE" + clean_up else echo "$DATE Testing against $TESTHOST ($PROTO) with $MAXSESSIONS simultaneous sessions while pinging $PINGHOST ($TESTDUR seconds in each direction)" diff --git a/lib/summarize_pings.sh b/lib/summarize_pings.sh new file mode 100644 index 0000000..8729338 --- /dev/null +++ b/lib/summarize_pings.sh @@ -0,0 +1,46 @@ +summarize_pings() { + + # Process the ping times from the passed-in file, and summarize the results + # grep to keep lines that have "time=", then sed to isolate the time stamps, and sort them + # Use awk to build an array of those values, and print first & last (which are min, max) + # and compute average. + # If the number of samples is >= 10, also compute median, and 10th and 90th percentile readings + + # Display the values as: + # Latency: (in msec, 11 pings, 8.33% packet loss) + # Min: 16.556 + # 10pct: 16.561 + # Median: 22.370 + # Avg: 21.203 + # 90pct: 23.202 + # Max: 23.394 + +grep "time" < "$1" | cat | \ +sed 's/^.*time=\([^ ]*\) ms/\1/'| \ + # tee >&2 | \ + sort -n | \ + awk 'BEGIN {numdrops=0; numrows=0} \ + { \ + # print ; \ + if ( $0 ~ /timeout/ ) { \ + numdrops += 1; \ + } else { \ + numrows += 1; \ + arr[numrows]=$1; sum+=$1; \ + } \ + } \ + END { \ + pc10="-"; pc90="-"; med="-"; \ + if (numrows == 0) {numrows=1} \ + if (numrows>=10) \ + { # get the 10th pctile - never the first one + ix=int(numrows/10); if (ix=1) {ix+=1}; pc10=arr[ix]; \ + # get the 90th pctile + ix=int(numrows*9/10);pc90=arr[ix]; \ + # get the median + if (numrows%2==1) med=arr[(numrows+1)/2]; else med=(arr[numrows/2]); \ + }; \ + pktloss = numdrops/(numdrops+numrows) * 100; \ + printf("\n Latency: (in msec, %d pings, %4.2f%% packet loss)\n Min: %4.3f \n 10pct: %4.3f \n Median: %4.3f \n Avg: %4.3f \n 90pct: %4.3f \n Max: %4.3f\n", numrows, pktloss, arr[1], pc10, med, sum/numrows, pc90, arr[numrows] )\ + }' +} \ No newline at end of file diff --git a/tests/pingsamples.txt b/tests/pingsamples.txt new file mode 100644 index 0000000..cf66089 --- /dev/null +++ b/tests/pingsamples.txt @@ -0,0 +1,88 @@ +PING 1.1.1.1 (1.1.1.1): 56 data bytes +64 bytes from 1.1.1.1: icmp_seq=0 ttl=55 time=22.370 ms +64 bytes from 1.1.1.1: icmp_seq=1 ttl=55 time=22.639 ms +64 bytes from 1.1.1.1: icmp_seq=2 ttl=55 time=23.202 ms +64 bytes from 1.1.1.1: icmp_seq=3 ttl=55 time=16.561 ms +64 bytes from 1.1.1.1: icmp_seq=4 ttl=55 time=23.394 ms +64 bytes from 1.1.1.1: icmp_seq=5 ttl=55 time=22.348 ms +64 bytes from 1.1.1.1: icmp_seq=6 ttl=55 time=23.250 ms +64 bytes from 1.1.1.1: icmp_seq=7 ttl=55 time=16.556 ms +Request timeout for icmp_seq 8 +64 bytes from 1.1.1.1: icmp_seq=9 ttl=55 time=22.247 ms +64 bytes from 1.1.1.1: icmp_seq=10 ttl=55 time=17.617 ms +64 bytes from 1.1.1.1: icmp_seq=11 ttl=55 time=23.049 ms +64 bytes from 1.1.1.1: icmp_seq=12 ttl=55 time=16.619 ms +64 bytes from 1.1.1.1: icmp_seq=13 ttl=55 time=22.737 ms +64 bytes from 1.1.1.1: icmp_seq=14 ttl=55 time=22.806 ms +64 bytes from 1.1.1.1: icmp_seq=15 ttl=55 time=22.971 ms +64 bytes from 1.1.1.1: icmp_seq=16 ttl=55 time=16.498 ms +64 bytes from 1.1.1.1: icmp_seq=17 ttl=55 time=23.385 ms +64 bytes from 1.1.1.1: icmp_seq=18 ttl=55 time=22.898 ms +64 bytes from 1.1.1.1: icmp_seq=19 ttl=55 time=22.988 ms +64 bytes from 1.1.1.1: icmp_seq=20 ttl=55 time=23.051 ms +64 bytes from 1.1.1.1: icmp_seq=21 ttl=55 time=16.487 ms +64 bytes from 1.1.1.1: icmp_seq=22 ttl=55 time=16.692 ms +64 bytes from 1.1.1.1: icmp_seq=23 ttl=55 time=15.711 ms +64 bytes from 1.1.1.1: icmp_seq=24 ttl=55 time=17.799 ms +64 bytes from 1.1.1.1: icmp_seq=25 ttl=55 time=23.230 ms +64 bytes from 1.1.1.1: icmp_seq=26 ttl=55 time=22.493 ms +64 bytes from 1.1.1.1: icmp_seq=27 ttl=55 time=23.209 ms +64 bytes from 1.1.1.1: icmp_seq=28 ttl=55 time=22.708 ms +64 bytes from 1.1.1.1: icmp_seq=29 ttl=55 time=22.146 ms +64 bytes from 1.1.1.1: icmp_seq=30 ttl=55 time=22.887 ms +64 bytes from 1.1.1.1: icmp_seq=31 ttl=55 time=23.119 ms +64 bytes from 1.1.1.1: icmp_seq=32 ttl=55 time=23.049 ms +64 bytes from 1.1.1.1: icmp_seq=33 ttl=55 time=17.061 ms +64 bytes from 1.1.1.1: icmp_seq=34 ttl=55 time=23.603 ms +64 bytes from 1.1.1.1: icmp_seq=35 ttl=55 time=16.382 ms +64 bytes from 1.1.1.1: icmp_seq=36 ttl=55 time=23.197 ms +64 bytes from 1.1.1.1: icmp_seq=37 ttl=55 time=17.043 ms +64 bytes from 1.1.1.1: icmp_seq=38 ttl=55 time=25.956 ms +64 bytes from 1.1.1.1: icmp_seq=39 ttl=55 time=23.118 ms +64 bytes from 1.1.1.1: icmp_seq=40 ttl=55 time=23.350 ms +64 bytes from 1.1.1.1: icmp_seq=41 ttl=55 time=23.614 ms +64 bytes from 1.1.1.1: icmp_seq=42 ttl=55 time=16.343 ms +64 bytes from 1.1.1.1: icmp_seq=43 ttl=55 time=28.280 ms +64 bytes from 1.1.1.1: icmp_seq=44 ttl=55 time=23.024 ms +64 bytes from 1.1.1.1: icmp_seq=45 ttl=55 time=22.868 ms +64 bytes from 1.1.1.1: icmp_seq=46 ttl=55 time=16.664 ms +64 bytes from 1.1.1.1: icmp_seq=47 ttl=55 time=22.922 ms +64 bytes from 1.1.1.1: icmp_seq=48 ttl=55 time=23.331 ms +64 bytes from 1.1.1.1: icmp_seq=49 ttl=55 time=23.770 ms +64 bytes from 1.1.1.1: icmp_seq=50 ttl=55 time=22.904 ms +64 bytes from 1.1.1.1: icmp_seq=51 ttl=55 time=23.393 ms +64 bytes from 1.1.1.1: icmp_seq=52 ttl=55 time=22.398 ms +64 bytes from 1.1.1.1: icmp_seq=53 ttl=55 time=18.838 ms +64 bytes from 1.1.1.1: icmp_seq=54 ttl=55 time=17.159 ms +64 bytes from 1.1.1.1: icmp_seq=55 ttl=55 time=23.008 ms +64 bytes from 1.1.1.1: icmp_seq=56 ttl=55 time=23.543 ms +64 bytes from 1.1.1.1: icmp_seq=57 ttl=55 time=16.356 ms +64 bytes from 1.1.1.1: icmp_seq=58 ttl=55 time=16.766 ms +64 bytes from 1.1.1.1: icmp_seq=59 ttl=55 time=22.899 ms +64 bytes from 1.1.1.1: icmp_seq=60 ttl=55 time=23.018 ms +64 bytes from 1.1.1.1: icmp_seq=61 ttl=55 time=16.107 ms +64 bytes from 1.1.1.1: icmp_seq=62 ttl=55 time=23.279 ms +64 bytes from 1.1.1.1: icmp_seq=63 ttl=55 time=17.151 ms +64 bytes from 1.1.1.1: icmp_seq=64 ttl=55 time=16.751 ms +64 bytes from 1.1.1.1: icmp_seq=65 ttl=55 time=23.201 ms +64 bytes from 1.1.1.1: icmp_seq=66 ttl=55 time=23.518 ms +64 bytes from 1.1.1.1: icmp_seq=67 ttl=55 time=23.008 ms +64 bytes from 1.1.1.1: icmp_seq=68 ttl=55 time=23.239 ms +64 bytes from 1.1.1.1: icmp_seq=69 ttl=55 time=22.914 ms +64 bytes from 1.1.1.1: icmp_seq=70 ttl=55 time=17.153 ms +64 bytes from 1.1.1.1: icmp_seq=71 ttl=55 time=22.090 ms +64 bytes from 1.1.1.1: icmp_seq=72 ttl=55 time=23.510 ms +64 bytes from 1.1.1.1: icmp_seq=73 ttl=55 time=23.084 ms +64 bytes from 1.1.1.1: icmp_seq=74 ttl=55 time=22.768 ms +64 bytes from 1.1.1.1: icmp_seq=75 ttl=55 time=22.237 ms +64 bytes from 1.1.1.1: icmp_seq=76 ttl=55 time=23.340 ms +64 bytes from 1.1.1.1: icmp_seq=77 ttl=55 time=16.883 ms +64 bytes from 1.1.1.1: icmp_seq=78 ttl=55 time=23.954 ms +64 bytes from 1.1.1.1: icmp_seq=79 ttl=55 time=23.415 ms +64 bytes from 1.1.1.1: icmp_seq=80 ttl=55 time=16.897 ms +64 bytes from 1.1.1.1: icmp_seq=81 ttl=55 time=18.440 ms +64 bytes from 1.1.1.1: icmp_seq=82 ttl=55 time=20.889 ms + +--- 1.1.1.1 ping statistics --- +83 packets transmitted, 83 packets received, 0.0% packet loss +round-trip min/avg/max/stddev = 15.711/21.256/28.280/2.984 ms diff --git a/tests/test_summary.sh b/tests/test_summary.sh new file mode 100644 index 0000000..179f3f0 --- /dev/null +++ b/tests/test_summary.sh @@ -0,0 +1,23 @@ +# Test scaffolding for the summarize_pings() subroutine. +# Take a known set of ping readings (in ./pingsamples.txt), strip out bogus stuff, +# then pass the first N lines (passed in as an argument) to the summarize_pings() function +# + +# include the summarize_pings() function from the library +. "../lib/summarize_pings.sh" + +PINGFILE=$(mktemp /tmp/measurepings.XXXXXX) || exit 1 + +# pre-format the pingsamples for ease of counting... +# strip out any line that doesn't contain "time" (e.g., not time= or timeout) +# Only send the specified number of lines into $PINGFILE +cat < pingsamples.txt | \ +grep time | \ +head -n "$1" > "$PINGFILE" +echo "=== PINGFILE ===" +cat "$PINGFILE" +echo "========" +summarize_pings "$PINGFILE" +rm "$PINGFILE" + +