1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/python2 2*c8dee2aaSAndroid Build Coastguard Worker# 3*c8dee2aaSAndroid Build Coastguard Worker# Copyright 2019 Google Inc. 4*c8dee2aaSAndroid Build Coastguard Worker# 5*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 6*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file. 7*c8dee2aaSAndroid Build Coastguard Worker# 8*c8dee2aaSAndroid Build Coastguard Worker# Helper script that takes as input 2 CSVs downloaded from perf.skia.org and 9*c8dee2aaSAndroid Build Coastguard Worker# outputs a CSV with test_name, avg_value1 (from CSV1), avg_value2 (from CSV2), 10*c8dee2aaSAndroid Build Coastguard Worker# perc_diff between avg_value1 and avg_value2. 11*c8dee2aaSAndroid Build Coastguard Worker# This script also discards NUM_OUTLIERS_TO_REMOVE min values and 12*c8dee2aaSAndroid Build Coastguard Worker# NUM_OUTLIERS_TO_REMOVE max values. 13*c8dee2aaSAndroid Build Coastguard Worker 14*c8dee2aaSAndroid Build Coastguard Worker 15*c8dee2aaSAndroid Build Coastguard Workerimport csv 16*c8dee2aaSAndroid Build Coastguard Workerimport optparse 17*c8dee2aaSAndroid Build Coastguard Workerimport sys 18*c8dee2aaSAndroid Build Coastguard Workerimport re 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard WorkerMISSING_STR = 'N/A' 22*c8dee2aaSAndroid Build Coastguard WorkerNUM_OUTLIERS_TO_REMOVE = 2 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker 25*c8dee2aaSAndroid Build Coastguard Workerdef read_from_csv(csv_file): 26*c8dee2aaSAndroid Build Coastguard Worker test_to_avg = {} 27*c8dee2aaSAndroid Build Coastguard Worker with open(csv_file, 'rb') as f: 28*c8dee2aaSAndroid Build Coastguard Worker csv_reader = csv.reader(f, delimiter=',') 29*c8dee2aaSAndroid Build Coastguard Worker # First row should contain headers. Validate that it does. 30*c8dee2aaSAndroid Build Coastguard Worker header_row = csv_reader.next() 31*c8dee2aaSAndroid Build Coastguard Worker if header_row[0] != 'id': 32*c8dee2aaSAndroid Build Coastguard Worker raise Exception('%s in unexpected format' % csv_file) 33*c8dee2aaSAndroid Build Coastguard Worker p = re.compile('^.*,test=(.*),$') 34*c8dee2aaSAndroid Build Coastguard Worker for v in csv_reader: 35*c8dee2aaSAndroid Build Coastguard Worker # Extract the test name. 36*c8dee2aaSAndroid Build Coastguard Worker result = p.search(v[0]) 37*c8dee2aaSAndroid Build Coastguard Worker test_name = result.group(1) 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker vals = [float(i) for i in v[1:]] 40*c8dee2aaSAndroid Build Coastguard Worker vals.sort() 41*c8dee2aaSAndroid Build Coastguard Worker # Discard outliers. 42*c8dee2aaSAndroid Build Coastguard Worker vals = vals[NUM_OUTLIERS_TO_REMOVE:-NUM_OUTLIERS_TO_REMOVE] 43*c8dee2aaSAndroid Build Coastguard Worker # Find the avg val. 44*c8dee2aaSAndroid Build Coastguard Worker avg_val = reduce(lambda x, y: x+y, vals) / float(len(vals)) 45*c8dee2aaSAndroid Build Coastguard Worker test_to_avg[test_name] = avg_val 46*c8dee2aaSAndroid Build Coastguard Worker return test_to_avg 47*c8dee2aaSAndroid Build Coastguard Worker 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Workerdef combine_results(d1, d2): 50*c8dee2aaSAndroid Build Coastguard Worker test_to_result = {} 51*c8dee2aaSAndroid Build Coastguard Worker for test1, v1 in d1.items(): 52*c8dee2aaSAndroid Build Coastguard Worker v2 = d2.get(test1, MISSING_STR) 53*c8dee2aaSAndroid Build Coastguard Worker perc_diff = MISSING_STR 54*c8dee2aaSAndroid Build Coastguard Worker if v2 != MISSING_STR: 55*c8dee2aaSAndroid Build Coastguard Worker diff = v2 - v1 56*c8dee2aaSAndroid Build Coastguard Worker avg = (v2 + v1)/2 57*c8dee2aaSAndroid Build Coastguard Worker perc_diff = 0 if avg == 0 else diff/avg * 100 58*c8dee2aaSAndroid Build Coastguard Worker result = { 59*c8dee2aaSAndroid Build Coastguard Worker 'test_name': test1, 60*c8dee2aaSAndroid Build Coastguard Worker 'csv1': v1, 61*c8dee2aaSAndroid Build Coastguard Worker 'csv2': v2, 62*c8dee2aaSAndroid Build Coastguard Worker 'perc_diff': perc_diff, 63*c8dee2aaSAndroid Build Coastguard Worker } 64*c8dee2aaSAndroid Build Coastguard Worker test_to_result[test1] = result 65*c8dee2aaSAndroid Build Coastguard Worker 66*c8dee2aaSAndroid Build Coastguard Worker # Also add keys in d2 and not d1. 67*c8dee2aaSAndroid Build Coastguard Worker for test2, v2 in d2.items(): 68*c8dee2aaSAndroid Build Coastguard Worker if test2 in test_to_result: 69*c8dee2aaSAndroid Build Coastguard Worker continue 70*c8dee2aaSAndroid Build Coastguard Worker test_to_result[test2] = { 71*c8dee2aaSAndroid Build Coastguard Worker 'test_name': test2, 72*c8dee2aaSAndroid Build Coastguard Worker 'csv1': MISSING_STR, 73*c8dee2aaSAndroid Build Coastguard Worker 'csv2': v2, 74*c8dee2aaSAndroid Build Coastguard Worker 'perc_diff': MISSING_STR, 75*c8dee2aaSAndroid Build Coastguard Worker } 76*c8dee2aaSAndroid Build Coastguard Worker 77*c8dee2aaSAndroid Build Coastguard Worker return test_to_result 78*c8dee2aaSAndroid Build Coastguard Worker 79*c8dee2aaSAndroid Build Coastguard Worker 80*c8dee2aaSAndroid Build Coastguard Workerdef write_to_csv(output_dict, output_csv): 81*c8dee2aaSAndroid Build Coastguard Worker with open(output_csv, 'w') as f: 82*c8dee2aaSAndroid Build Coastguard Worker fieldnames = ['test_name', 'csv1', 'csv2', 'perc_diff'] 83*c8dee2aaSAndroid Build Coastguard Worker writer = csv.DictWriter(f, fieldnames=fieldnames) 84*c8dee2aaSAndroid Build Coastguard Worker writer.writeheader() 85*c8dee2aaSAndroid Build Coastguard Worker tests = output_dict.keys() 86*c8dee2aaSAndroid Build Coastguard Worker tests.sort() 87*c8dee2aaSAndroid Build Coastguard Worker for test in tests: 88*c8dee2aaSAndroid Build Coastguard Worker writer.writerow(output_dict[test]) 89*c8dee2aaSAndroid Build Coastguard Worker 90*c8dee2aaSAndroid Build Coastguard Worker 91*c8dee2aaSAndroid Build Coastguard Workerdef parse_and_output(csv1, csv2, output_csv): 92*c8dee2aaSAndroid Build Coastguard Worker test_to_avg1 = read_from_csv(csv1) 93*c8dee2aaSAndroid Build Coastguard Worker test_to_avg2 = read_from_csv(csv2) 94*c8dee2aaSAndroid Build Coastguard Worker output_dict = combine_results(test_to_avg1, test_to_avg2) 95*c8dee2aaSAndroid Build Coastguard Worker write_to_csv(output_dict, output_csv) 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Workerdef main(): 99*c8dee2aaSAndroid Build Coastguard Worker option_parser = optparse.OptionParser() 100*c8dee2aaSAndroid Build Coastguard Worker option_parser.add_option( 101*c8dee2aaSAndroid Build Coastguard Worker '', '--csv1', type=str, 102*c8dee2aaSAndroid Build Coastguard Worker help='The first CSV to parse.') 103*c8dee2aaSAndroid Build Coastguard Worker option_parser.add_option( 104*c8dee2aaSAndroid Build Coastguard Worker '', '--csv2', type=str, 105*c8dee2aaSAndroid Build Coastguard Worker help='The second CSV to parse.') 106*c8dee2aaSAndroid Build Coastguard Worker option_parser.add_option( 107*c8dee2aaSAndroid Build Coastguard Worker '', '--output_csv', type=str, 108*c8dee2aaSAndroid Build Coastguard Worker help='The file to write the output CSV to.') 109*c8dee2aaSAndroid Build Coastguard Worker options, _ = option_parser.parse_args() 110*c8dee2aaSAndroid Build Coastguard Worker sys.exit(parse_and_output(options.csv1, options.csv2, options.output_csv)) 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Worker 113*c8dee2aaSAndroid Build Coastguard Workerif __name__ == '__main__': 114*c8dee2aaSAndroid Build Coastguard Worker main() 115