summaryrefslogtreecommitdiffstats
path: root/contrib/iperf3_to_gnuplot.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/iperf3_to_gnuplot.py')
-rwxr-xr-xcontrib/iperf3_to_gnuplot.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/contrib/iperf3_to_gnuplot.py b/contrib/iperf3_to_gnuplot.py
new file mode 100755
index 0000000..6a1f7a0
--- /dev/null
+++ b/contrib/iperf3_to_gnuplot.py
@@ -0,0 +1,124 @@
+#!/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()