xref: /iperf/contrib/iperf3_to_gnuplot.py (revision 897687ac)
1c50b5ea8SBrian Tierney#!/usr/bin/env python
2c50b5ea8SBrian Tierney
3c50b5ea8SBrian Tierney"""
4c50b5ea8SBrian TierneyExtract iperf data from json blob and format for gnuplot.
5c50b5ea8SBrian Tierney"""
6c50b5ea8SBrian Tierney
7c50b5ea8SBrian Tierneyimport json
8c50b5ea8SBrian Tierneyimport os
9c50b5ea8SBrian Tierneyimport sys
10c50b5ea8SBrian Tierney
11c50b5ea8SBrian Tierneyfrom optparse import OptionParser
12c50b5ea8SBrian Tierney
13c50b5ea8SBrian Tierneyimport pprint
14c50b5ea8SBrian Tierney# for debugging, so output to stderr to keep verbose
15c50b5ea8SBrian Tierney# output out of any redirected stdout.
16c50b5ea8SBrian Tierneypp = pprint.PrettyPrinter(indent=4, stream=sys.stderr)
17c50b5ea8SBrian Tierney
182d3eb211SMonte Goode
19c50b5ea8SBrian Tierneydef generate_output(iperf, options):
202d3eb211SMonte Goode    """Do the actual formatting."""
21c50b5ea8SBrian Tierney    for i in iperf.get('intervals'):
22c50b5ea8SBrian Tierney        for ii in i.get('streams'):
232d3eb211SMonte Goode            if options.verbose:
242d3eb211SMonte Goode                pp.pprint(ii)
25c50b5ea8SBrian Tierney            row = '{0} {1} {2} {3} {4}\n'.format(
26c50b5ea8SBrian Tierney                round(float(ii.get('start')), 4),
27c50b5ea8SBrian Tierney                ii.get('bytes'),
28c50b5ea8SBrian Tierney                # to Gbits/sec
29c50b5ea8SBrian Tierney                round(float(ii.get('bits_per_second')) / (1000*1000*1000), 3),
30c50b5ea8SBrian Tierney                ii.get('retransmits'),
31c50b5ea8SBrian Tierney                round(float(ii.get('snd_cwnd')) / (1000*1000), 2)
32c50b5ea8SBrian Tierney            )
33c50b5ea8SBrian Tierney            yield row
34c50b5ea8SBrian Tierney
352d3eb211SMonte Goode
36471aa5f1SMonte Goodedef summed_output(iperf, options):
37471aa5f1SMonte Goode    """Format summed output."""
38471aa5f1SMonte Goode
39*897687acSMonte Goode    for i in iperf.get('intervals'):
40*897687acSMonte Goode
418d94dc28SMonte Goode        row_header = None
42471aa5f1SMonte Goode
43471aa5f1SMonte Goode        byte = list()
44471aa5f1SMonte Goode        bits_per_second = list()
45471aa5f1SMonte Goode        retransmits = list()
46471aa5f1SMonte Goode        snd_cwnd = list()
47471aa5f1SMonte Goode
48471aa5f1SMonte Goode        for ii in i.get('streams'):
49471aa5f1SMonte Goode            if options.verbose:
50471aa5f1SMonte Goode                pp.pprint(i)
518d94dc28SMonte Goode            # grab the first start value
528d94dc28SMonte Goode            if row_header is None:
53*897687acSMonte Goode                row_header = round(float(ii.get('start')), 2)
548d94dc28SMonte Goode            # aggregate the rest of the values
55471aa5f1SMonte Goode            byte.append(ii.get('bytes'))
56471aa5f1SMonte Goode            bits_per_second.append(float(ii.get('bits_per_second')) / (1000*1000*1000))
57471aa5f1SMonte Goode            retransmits.append(ii.get('retransmits'))
58471aa5f1SMonte Goode            snd_cwnd.append(float(ii.get('snd_cwnd')) / (1000*1000))
59471aa5f1SMonte Goode
60471aa5f1SMonte Goode        row = '{h} {b} {bps} {r} {s}\n'.format(
61471aa5f1SMonte Goode            h=row_header,
62471aa5f1SMonte Goode            b=sum(byte),
63471aa5f1SMonte Goode            bps=round(sum(bits_per_second), 3),
64471aa5f1SMonte Goode            r=sum(retransmits),
65471aa5f1SMonte Goode            s=round(sum(snd_cwnd) / len(snd_cwnd), 2)
66471aa5f1SMonte Goode        )
67471aa5f1SMonte Goode
68*897687acSMonte Goode        yield row
69471aa5f1SMonte Goode
70471aa5f1SMonte Goode
71c50b5ea8SBrian Tierneydef main():
722d3eb211SMonte Goode    """Execute the read and formatting."""
73c50b5ea8SBrian Tierney    usage = '%prog [ -f FILE | -o OUT | -v ]'
74c50b5ea8SBrian Tierney    parser = OptionParser(usage=usage)
75c50b5ea8SBrian Tierney    parser.add_option('-f', '--file', metavar='FILE',
76c50b5ea8SBrian Tierney                      type='string', dest='filename',
77c50b5ea8SBrian Tierney                      help='Input filename.')
78c50b5ea8SBrian Tierney    parser.add_option('-o', '--output', metavar='OUT',
79c50b5ea8SBrian Tierney                      type='string', dest='output',
80c50b5ea8SBrian Tierney                      help='Optional file to append output to.')
81471aa5f1SMonte Goode    parser.add_option('-s', '--sum',
82471aa5f1SMonte Goode                      dest='summed', action='store_true', default=False,
83471aa5f1SMonte Goode                      help='Summed version of the output.')
84c50b5ea8SBrian Tierney    parser.add_option('-v', '--verbose',
85c50b5ea8SBrian Tierney                      dest='verbose', action='store_true', default=False,
86c50b5ea8SBrian Tierney                      help='Verbose debug output to stderr.')
872d3eb211SMonte Goode    options, _ = parser.parse_args()
88c50b5ea8SBrian Tierney
89c50b5ea8SBrian Tierney    if not options.filename:
90c50b5ea8SBrian Tierney        parser.error('Filename is required.')
91c50b5ea8SBrian Tierney
92c50b5ea8SBrian Tierney    file_path = os.path.normpath(options.filename)
93c50b5ea8SBrian Tierney
94c50b5ea8SBrian Tierney    if not os.path.exists(file_path):
95c50b5ea8SBrian Tierney        parser.error('{f} does not exist'.format(f=file_path))
96c50b5ea8SBrian Tierney
97c50b5ea8SBrian Tierney    with open(file_path, 'r') as fh:
98c50b5ea8SBrian Tierney        data = fh.read()
99c50b5ea8SBrian Tierney
100c50b5ea8SBrian Tierney    try:
101c50b5ea8SBrian Tierney        iperf = json.loads(data)
1022d3eb211SMonte Goode    except Exception as ex:  # pylint: disable=broad-except
1032d3eb211SMonte Goode        parser.error('Could not parse JSON from file (ex): {0}'.format(str(ex)))
104c50b5ea8SBrian Tierney
105c50b5ea8SBrian Tierney    if options.output:
106c50b5ea8SBrian Tierney        absp = os.path.abspath(options.output)
1072d3eb211SMonte Goode        output_dir, _ = os.path.split(absp)
1082d3eb211SMonte Goode        if not os.path.exists(output_dir):
1092d3eb211SMonte Goode            parser.error('Output file directory path {0} does not exist'.format(output_dir))
110c50b5ea8SBrian Tierney        fh = open(absp, 'a')
111c50b5ea8SBrian Tierney    else:
112c50b5ea8SBrian Tierney        fh = sys.stdout
113c50b5ea8SBrian Tierney
114471aa5f1SMonte Goode    if options.summed:
115471aa5f1SMonte Goode        fmt = summed_output
116471aa5f1SMonte Goode    else:
117471aa5f1SMonte Goode        fmt = generate_output
118471aa5f1SMonte Goode
119471aa5f1SMonte Goode    for i in fmt(iperf, options):
120c50b5ea8SBrian Tierney        fh.write(i)
121c50b5ea8SBrian Tierney
122c50b5ea8SBrian Tierney
123c50b5ea8SBrian Tierneyif __name__ == '__main__':
124c50b5ea8SBrian Tierney    main()
125