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