xref: /aosp_15_r20/external/skia/tools/skottie-wasm-perf/parse_perf_csvs.py (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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