|
| 1 | +#!/bin/bash |
| 2 | +# |
| 3 | +# Title: multi-iperf.sh |
| 4 | +# Description: A helper script for making parallel iperf sessions. |
| 5 | +# Author: Rok Strnisa <rok@strnisa.com> |
| 6 | +# Source: https://github.com/perf101/scripts |
| 7 | + |
| 8 | +# DEFAULTS |
| 9 | +AGGREGATE=false |
| 10 | +BASENAME=`basename ${0}` |
| 11 | +B_SIZE= |
| 12 | +OUT= |
| 13 | +SIMPLE=false |
| 14 | +THREADS=1 |
| 15 | +TIME=5 |
| 16 | +VERBOSE=false |
| 17 | +declare -a VMIPs |
| 18 | +VMS= |
| 19 | +W_SIZE= |
| 20 | +XENTOP_HOST= |
| 21 | + |
| 22 | +# USAGE |
| 23 | +USAGE_PREFIX="Usage: ${BASENAME} " |
| 24 | +INDENT=`printf "%${#USAGE_PREFIX}s" " "` |
| 25 | +USAGE="${USAGE_PREFIX}[-h|--help] [-i <IP,IP,..>] [-n <INT>] [-t <INT>] |
| 26 | +${INDENT}[-o <PATH>|--output <PATH>] [-P <INT>] [-x <HOST>] |
| 27 | +${INDENT}[-b <INT>] [-w <INT>] [-f] [-v] [-a] |
| 28 | +
|
| 29 | + -a |
| 30 | + Output aggregate network throughput (in Mbps) to standard output. |
| 31 | +
|
| 32 | + -b <INT> |
| 33 | + Iperf buffer size in KB to use. The receiving side should probably use |
| 34 | + the same buffer size. Default depends on your Iperf implementation and |
| 35 | + your system. |
| 36 | +
|
| 37 | + -f |
| 38 | + Fix Iperf buffer size (-b) and window size (-w) to 256KB. Recommended |
| 39 | + when sending traffic to Windows VMs. (Iperfs on those VMs should |
| 40 | + probably use the same buffer and window size.) |
| 41 | +
|
| 42 | + -h, --help |
| 43 | + Show usage instructions. |
| 44 | +
|
| 45 | + -i <IP,IP,..> |
| 46 | + A comma-separated list of VM IPs. Used for establishing Iperf sessions |
| 47 | + with the VMs. The number of IPs must be equal or greater than the number |
| 48 | + specified for -n. No default. |
| 49 | +
|
| 50 | + -n <INT> |
| 51 | + Create concurrent Iperf sessions with <INT> VMs. Must be smaller than or |
| 52 | + equal to the number of IPs specified in -i. Default is the number of IPs |
| 53 | + specified with -i. |
| 54 | +
|
| 55 | + -o <PATH>, --output <PATH> |
| 56 | + Save results (in Mbps) into the file at <PATH> instead of outputting |
| 57 | + them to standard output. |
| 58 | +
|
| 59 | + -P <INT> |
| 60 | + Create <INT> Iperf threads per Iperf session. Default is ${THREADS}. |
| 61 | +
|
| 62 | + -s |
| 63 | + Simple output. Only outputs the aggregate number (in Mbps). Implies -a. |
| 64 | +
|
| 65 | + -t <INT> |
| 66 | + Set the test to last <INT> seconds. Default is ${TIME}. Recommended is |
| 67 | + 60 or more. |
| 68 | +
|
| 69 | + -v |
| 70 | + Verbose. At the moment, this only shows the final Iperf configuration. |
| 71 | +
|
| 72 | + -w <INT> |
| 73 | + Iperf window size in KB to use. The receiving side should probably use |
| 74 | + the same window size. Default depends on your Iperf implementation and |
| 75 | + your system. |
| 76 | +
|
| 77 | + -x <HOST> |
| 78 | + Specify a <HOST> (any address reachable via SSH without user interaction) |
| 79 | + for which to track CPU usage via xentop. The resolution is one xentop |
| 80 | + snapshot per second. The output is stored in _xentop, or <PATH>_xentop |
| 81 | + where <PATH> is the argument for -o. |
| 82 | +" |
| 83 | + |
| 84 | +# OVERRIDE DEFAULTS WITH ARGUMENTS |
| 85 | +while [ -n "${1}" ]; do |
| 86 | + case ${1} in |
| 87 | + -a) AGGREGATE=true;; |
| 88 | + -b) shift; B_SIZE=${1};; |
| 89 | + -f) B_SIZE=256; W_SIZE=256;; |
| 90 | + -h | --help) echo "${USAGE}" | less -FX; exit;; |
| 91 | + -i) shift; IFS=',' read -ra VMIPs <<< "${1}";; |
| 92 | + -n) shift; VMS=${1};; |
| 93 | + -o | --output) shift; OUT=${1};; |
| 94 | + -P) shift; THREADS=${1};; |
| 95 | + -s) AGGREGATE=true; SIMPLE=true;; |
| 96 | + -t) shift; TIME=${1};; |
| 97 | + -v) VERBOSE=true;; |
| 98 | + -w) shift; W_SIZE=${1};; |
| 99 | + -x) shift; XENTOP_HOST=${1};; |
| 100 | + *) echo "${USAGE}" | less -FX; exit 1 |
| 101 | + esac |
| 102 | + shift |
| 103 | +done |
| 104 | + |
| 105 | +# VARIABLE CONSISTENCY CHECK AND POSTPROCESSING |
| 106 | +if [ -z "${VMS}" ]; then |
| 107 | + VMS=${#VMIPs[@]} |
| 108 | +fi |
| 109 | +if [ ${VMS} -gt ${#VMIPs[@]} ]; then |
| 110 | + echo "Error: # VMs (-n) is greater than # IPs (-VMIPs): ${VMS} > ${#VMIPs[@]}." |
| 111 | + echo "See usage instructions with: $0 -h" |
| 112 | + exit 1 |
| 113 | +fi |
| 114 | +if [ -n "${B_SIZE}" ]; then |
| 115 | + B_SIZE=" -l ${B_SIZE}K" |
| 116 | +fi |
| 117 | +if [ -n "${W_SIZE}" ]; then |
| 118 | + W_SIZE=" -w ${W_SIZE}K" |
| 119 | +fi |
| 120 | +XENTOP_OUT="${OUT}_xentop" |
| 121 | + |
| 122 | +# START RECORDING XENTOP USAGE ON RECEIVER |
| 123 | +if [ -n "${XENTOP_HOST}" ]; then |
| 124 | + if ${VERBOSE}; then echo "Starting xentop logging for ${XENTOP_HOST} .."; fi |
| 125 | + ssh ${XENTOP_HOST} "xentop -b -d 1 -f" > "${XENTOP_OUT}" & |
| 126 | + PID=${!} |
| 127 | + if ${VERBOSE}; then echo "Output file for xentop logging: ${XENTOP_OUT}"; fi |
| 128 | +fi |
| 129 | + |
| 130 | +# START PARALLEL IPERF SESSIONS |
| 131 | +IPERF_CMD="iperf${B_SIZE}${W_SIZE} -t ${TIME} -P ${THREADS}" |
| 132 | +if ${VERBOSE}; then echo "Using Iperf command: ${IPERF_CMD}"; fi |
| 133 | +TMP=`mktemp` |
| 134 | +for i in `seq ${VMS}`; do |
| 135 | + VM_IP=${VMIPs[i-1]} |
| 136 | + if ${VERBOSE}; then echo "Connecting to ${VM_IP} .."; fi |
| 137 | + ${IPERF_CMD} -c ${VM_IP} -f m \ |
| 138 | + | grep -o "[0-9]\+ Mbits/sec" \ |
| 139 | + | awk -vIP=${VM_IP} '{print IP, $1}' \ |
| 140 | + >> ${TMP} & |
| 141 | +done |
| 142 | + |
| 143 | +# WAIT FOR THE TESTS TO COMPLETE |
| 144 | +sleep $((TIME + 3)) |
| 145 | + |
| 146 | +# STOP RECORDING XENTOP USAGE |
| 147 | +if [ -n "${XENTOP_HOST}" ]; then |
| 148 | + if ${VERBOSE}; then echo "Stopping xentop logging for ${XENTOP_HOST} .."; fi |
| 149 | + kill ${PID}; |
| 150 | +fi |
| 151 | + |
| 152 | +# SORT INDIVIDUAL RESULTS |
| 153 | +TMP2=`mktemp` |
| 154 | +if ! ${SIMPLE}; then sort -o ${TMP2} ${TMP}; fi |
| 155 | + |
| 156 | +# OUTPUT AGGREGATE THROUGHPUT TO STDOUT |
| 157 | +if ${AGGREGATE}; then |
| 158 | + if ! ${SIMPLE}; then echo -n "AGGREGATE " >> ${TMP2}; fi |
| 159 | + cat "${TMP}" | awk '{sum+=$2}END{print sum}' >> ${TMP2} |
| 160 | +fi |
| 161 | + |
| 162 | +# OUTPUT RESULTS |
| 163 | +if [ -n "${OUT}" ]; then |
| 164 | + cp ${TMP2} ${OUT} |
| 165 | +else |
| 166 | + cat ${TMP2} |
| 167 | +fi |
| 168 | + |
| 169 | +# REMOVE TEMPORARY FILES |
| 170 | +rm -f ${TMP} ${TMP2} |
0 commit comments