1*7ab6e6acSAndroid Build Coastguard Worker#!/usr/bin/env python 2*7ab6e6acSAndroid Build Coastguard Worker 3*7ab6e6acSAndroid Build Coastguard Worker""" 4*7ab6e6acSAndroid Build Coastguard WorkerExtract iperf data from json blob and format for gnuplot. 5*7ab6e6acSAndroid Build Coastguard Worker""" 6*7ab6e6acSAndroid Build Coastguard Worker 7*7ab6e6acSAndroid Build Coastguard Workerimport json 8*7ab6e6acSAndroid Build Coastguard Workerimport os 9*7ab6e6acSAndroid Build Coastguard Workerimport sys 10*7ab6e6acSAndroid Build Coastguard Worker 11*7ab6e6acSAndroid Build Coastguard Workerfrom optparse import OptionParser 12*7ab6e6acSAndroid Build Coastguard Worker 13*7ab6e6acSAndroid Build Coastguard Workerimport pprint 14*7ab6e6acSAndroid Build Coastguard Worker# for debugging, so output to stderr to keep verbose 15*7ab6e6acSAndroid Build Coastguard Worker# output out of any redirected stdout. 16*7ab6e6acSAndroid Build Coastguard Workerpp = pprint.PrettyPrinter(indent=4, stream=sys.stderr) 17*7ab6e6acSAndroid Build Coastguard Worker 18*7ab6e6acSAndroid Build Coastguard Worker 19*7ab6e6acSAndroid Build Coastguard Workerdef generate_output(iperf, options): 20*7ab6e6acSAndroid Build Coastguard Worker """Do the actual formatting.""" 21*7ab6e6acSAndroid Build Coastguard Worker for i in iperf.get('intervals'): 22*7ab6e6acSAndroid Build Coastguard Worker for ii in i.get('streams'): 23*7ab6e6acSAndroid Build Coastguard Worker if options.verbose: 24*7ab6e6acSAndroid Build Coastguard Worker pp.pprint(ii) 25*7ab6e6acSAndroid Build Coastguard Worker row = '{0} {1} {2} {3} {4}\n'.format( 26*7ab6e6acSAndroid Build Coastguard Worker round(float(ii.get('start')), 4), 27*7ab6e6acSAndroid Build Coastguard Worker ii.get('bytes'), 28*7ab6e6acSAndroid Build Coastguard Worker # to Gbits/sec 29*7ab6e6acSAndroid Build Coastguard Worker round(float(ii.get('bits_per_second')) / (1000*1000*1000), 3), 30*7ab6e6acSAndroid Build Coastguard Worker ii.get('retransmits'), 31*7ab6e6acSAndroid Build Coastguard Worker round(float(ii.get('snd_cwnd')) / (1000*1000), 2) 32*7ab6e6acSAndroid Build Coastguard Worker ) 33*7ab6e6acSAndroid Build Coastguard Worker yield row 34*7ab6e6acSAndroid Build Coastguard Worker 35*7ab6e6acSAndroid Build Coastguard Worker 36*7ab6e6acSAndroid Build Coastguard Workerdef summed_output(iperf, options): 37*7ab6e6acSAndroid Build Coastguard Worker """Format summed output.""" 38*7ab6e6acSAndroid Build Coastguard Worker 39*7ab6e6acSAndroid Build Coastguard Worker for i in iperf.get('intervals'): 40*7ab6e6acSAndroid Build Coastguard Worker 41*7ab6e6acSAndroid Build Coastguard Worker row_header = None 42*7ab6e6acSAndroid Build Coastguard Worker 43*7ab6e6acSAndroid Build Coastguard Worker byte = list() 44*7ab6e6acSAndroid Build Coastguard Worker bits_per_second = list() 45*7ab6e6acSAndroid Build Coastguard Worker retransmits = list() 46*7ab6e6acSAndroid Build Coastguard Worker snd_cwnd = list() 47*7ab6e6acSAndroid Build Coastguard Worker 48*7ab6e6acSAndroid Build Coastguard Worker for ii in i.get('streams'): 49*7ab6e6acSAndroid Build Coastguard Worker if options.verbose: 50*7ab6e6acSAndroid Build Coastguard Worker pp.pprint(i) 51*7ab6e6acSAndroid Build Coastguard Worker # grab the first start value 52*7ab6e6acSAndroid Build Coastguard Worker if row_header is None: 53*7ab6e6acSAndroid Build Coastguard Worker row_header = round(float(ii.get('start')), 2) 54*7ab6e6acSAndroid Build Coastguard Worker # aggregate the rest of the values 55*7ab6e6acSAndroid Build Coastguard Worker byte.append(ii.get('bytes')) 56*7ab6e6acSAndroid Build Coastguard Worker bits_per_second.append(float(ii.get('bits_per_second')) / (1000*1000*1000)) 57*7ab6e6acSAndroid Build Coastguard Worker retransmits.append(ii.get('retransmits')) 58*7ab6e6acSAndroid Build Coastguard Worker snd_cwnd.append(float(ii.get('snd_cwnd')) / (1000*1000)) 59*7ab6e6acSAndroid Build Coastguard Worker 60*7ab6e6acSAndroid Build Coastguard Worker row = '{h} {b} {bps} {r} {s}\n'.format( 61*7ab6e6acSAndroid Build Coastguard Worker h=row_header, 62*7ab6e6acSAndroid Build Coastguard Worker b=sum(byte), 63*7ab6e6acSAndroid Build Coastguard Worker bps=round(sum(bits_per_second), 3), 64*7ab6e6acSAndroid Build Coastguard Worker r=sum(retransmits), 65*7ab6e6acSAndroid Build Coastguard Worker s=round(sum(snd_cwnd) / len(snd_cwnd), 2) 66*7ab6e6acSAndroid Build Coastguard Worker ) 67*7ab6e6acSAndroid Build Coastguard Worker 68*7ab6e6acSAndroid Build Coastguard Worker yield row 69*7ab6e6acSAndroid Build Coastguard Worker 70*7ab6e6acSAndroid Build Coastguard Worker 71*7ab6e6acSAndroid Build Coastguard Workerdef main(): 72*7ab6e6acSAndroid Build Coastguard Worker """Execute the read and formatting.""" 73*7ab6e6acSAndroid Build Coastguard Worker usage = '%prog [ -f FILE | -o OUT | -v ]' 74*7ab6e6acSAndroid Build Coastguard Worker parser = OptionParser(usage=usage) 75*7ab6e6acSAndroid Build Coastguard Worker parser.add_option('-f', '--file', metavar='FILE', 76*7ab6e6acSAndroid Build Coastguard Worker type='string', dest='filename', 77*7ab6e6acSAndroid Build Coastguard Worker help='Input filename.') 78*7ab6e6acSAndroid Build Coastguard Worker parser.add_option('-o', '--output', metavar='OUT', 79*7ab6e6acSAndroid Build Coastguard Worker type='string', dest='output', 80*7ab6e6acSAndroid Build Coastguard Worker help='Optional file to append output to.') 81*7ab6e6acSAndroid Build Coastguard Worker parser.add_option('-s', '--sum', 82*7ab6e6acSAndroid Build Coastguard Worker dest='summed', action='store_true', default=False, 83*7ab6e6acSAndroid Build Coastguard Worker help='Summed version of the output.') 84*7ab6e6acSAndroid Build Coastguard Worker parser.add_option('-v', '--verbose', 85*7ab6e6acSAndroid Build Coastguard Worker dest='verbose', action='store_true', default=False, 86*7ab6e6acSAndroid Build Coastguard Worker help='Verbose debug output to stderr.') 87*7ab6e6acSAndroid Build Coastguard Worker options, _ = parser.parse_args() 88*7ab6e6acSAndroid Build Coastguard Worker 89*7ab6e6acSAndroid Build Coastguard Worker if not options.filename: 90*7ab6e6acSAndroid Build Coastguard Worker parser.error('Filename is required.') 91*7ab6e6acSAndroid Build Coastguard Worker 92*7ab6e6acSAndroid Build Coastguard Worker file_path = os.path.normpath(options.filename) 93*7ab6e6acSAndroid Build Coastguard Worker 94*7ab6e6acSAndroid Build Coastguard Worker if not os.path.exists(file_path): 95*7ab6e6acSAndroid Build Coastguard Worker parser.error('{f} does not exist'.format(f=file_path)) 96*7ab6e6acSAndroid Build Coastguard Worker 97*7ab6e6acSAndroid Build Coastguard Worker with open(file_path, 'r') as fh: 98*7ab6e6acSAndroid Build Coastguard Worker data = fh.read() 99*7ab6e6acSAndroid Build Coastguard Worker 100*7ab6e6acSAndroid Build Coastguard Worker try: 101*7ab6e6acSAndroid Build Coastguard Worker iperf = json.loads(data) 102*7ab6e6acSAndroid Build Coastguard Worker except Exception as ex: # pylint: disable=broad-except 103*7ab6e6acSAndroid Build Coastguard Worker parser.error('Could not parse JSON from file (ex): {0}'.format(str(ex))) 104*7ab6e6acSAndroid Build Coastguard Worker 105*7ab6e6acSAndroid Build Coastguard Worker if options.output: 106*7ab6e6acSAndroid Build Coastguard Worker absp = os.path.abspath(options.output) 107*7ab6e6acSAndroid Build Coastguard Worker output_dir, _ = os.path.split(absp) 108*7ab6e6acSAndroid Build Coastguard Worker if not os.path.exists(output_dir): 109*7ab6e6acSAndroid Build Coastguard Worker parser.error('Output file directory path {0} does not exist'.format(output_dir)) 110*7ab6e6acSAndroid Build Coastguard Worker fh = open(absp, 'a') 111*7ab6e6acSAndroid Build Coastguard Worker else: 112*7ab6e6acSAndroid Build Coastguard Worker fh = sys.stdout 113*7ab6e6acSAndroid Build Coastguard Worker 114*7ab6e6acSAndroid Build Coastguard Worker if options.summed: 115*7ab6e6acSAndroid Build Coastguard Worker fmt = summed_output 116*7ab6e6acSAndroid Build Coastguard Worker else: 117*7ab6e6acSAndroid Build Coastguard Worker fmt = generate_output 118*7ab6e6acSAndroid Build Coastguard Worker 119*7ab6e6acSAndroid Build Coastguard Worker for i in fmt(iperf, options): 120*7ab6e6acSAndroid Build Coastguard Worker fh.write(i) 121*7ab6e6acSAndroid Build Coastguard Worker 122*7ab6e6acSAndroid Build Coastguard Worker 123*7ab6e6acSAndroid Build Coastguard Workerif __name__ == '__main__': 124*7ab6e6acSAndroid Build Coastguard Worker main() 125