blob: 6a1f7a01fc1855165040afc281332f2ccf9307aa [file] [log] [blame]
#!/usr/bin/env python
"""
Extract iperf data from json blob and format for gnuplot.
"""
import json
import os
import sys
from optparse import OptionParser
import pprint
# for debugging, so output to stderr to keep verbose
# output out of any redirected stdout.
pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr)
def generate_output(iperf, options):
"""Do the actual formatting."""
for i in iperf.get('intervals'):
for ii in i.get('streams'):
if options.verbose:
pp.pprint(ii)
row = '{0} {1} {2} {3} {4}\n'.format(
round(float(ii.get('start')), 4),
ii.get('bytes'),
# to Gbits/sec
round(float(ii.get('bits_per_second')) / (1000*1000*1000), 3),
ii.get('retransmits'),
round(float(ii.get('snd_cwnd')) / (1000*1000), 2)
)
yield row
def summed_output(iperf, options):
"""Format summed output."""
for i in iperf.get('intervals'):
row_header = None
byte = list()
bits_per_second = list()
retransmits = list()
snd_cwnd = list()
for ii in i.get('streams'):
if options.verbose:
pp.pprint(i)
# grab the first start value
if row_header is None:
row_header = round(float(ii.get('start')), 2)
# aggregate the rest of the values
byte.append(ii.get('bytes'))
bits_per_second.append(float(ii.get('bits_per_second')) / (1000*1000*1000))
retransmits.append(ii.get('retransmits'))
snd_cwnd.append(float(ii.get('snd_cwnd')) / (1000*1000))
row = '{h} {b} {bps} {r} {s}\n'.format(
h=row_header,
b=sum(byte),
bps=round(sum(bits_per_second), 3),
r=sum(retransmits),
s=round(sum(snd_cwnd) / len(snd_cwnd), 2)
)
yield row
def main():
"""Execute the read and formatting."""
usage = '%prog [ -f FILE | -o OUT | -v ]'
parser = OptionParser(usage=usage)
parser.add_option('-f', '--file', metavar='FILE',
type='string', dest='filename',
help='Input filename.')
parser.add_option('-o', '--output', metavar='OUT',
type='string', dest='output',
help='Optional file to append output to.')
parser.add_option('-s', '--sum',
dest='summed', action='store_true', default=False,
help='Summed version of the output.')
parser.add_option('-v', '--verbose',
dest='verbose', action='store_true', default=False,
help='Verbose debug output to stderr.')
options, _ = parser.parse_args()
if not options.filename:
parser.error('Filename is required.')
file_path = os.path.normpath(options.filename)
if not os.path.exists(file_path):
parser.error('{f} does not exist'.format(f=file_path))
with open(file_path, 'r') as fh:
data = fh.read()
try:
iperf = json.loads(data)
except Exception as ex: # pylint: disable=broad-except
parser.error('Could not parse JSON from file (ex): {0}'.format(str(ex)))
if options.output:
absp = os.path.abspath(options.output)
output_dir, _ = os.path.split(absp)
if not os.path.exists(output_dir):
parser.error('Output file directory path {0} does not exist'.format(output_dir))
fh = open(absp, 'a')
else:
fh = sys.stdout
if options.summed:
fmt = summed_output
else:
fmt = generate_output
for i in fmt(iperf, options):
fh.write(i)
if __name__ == '__main__':
main()