blob: 546bebdfc3eaa6aed5535c12638ad353cbb8f528 [file] [log] [blame]
Austin Engca0eac32019-08-28 23:18:10 +00001#!/usr/bin/python2
2#
3# Copyright 2019 The Dawn Authors
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17# Based on Angle's perf_test_runner.py
18
19import glob
20import subprocess
21import sys
22import os
23import re
24
25base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
26
27# Look for a [Rr]elease build.
28perftests_paths = glob.glob('out/*elease*')
29metric = 'wall_time'
30max_experiments = 10
31
32binary_name = 'dawn_perf_tests'
33if sys.platform == 'win32':
34 binary_name += '.exe'
35
36scores = []
37
38def mean(data):
39 """Return the sample arithmetic mean of data."""
40 n = len(data)
41 if n < 1:
42 raise ValueError('mean requires at least one data point')
43 return float(sum(data)) / float(n) # in Python 2 use sum(data)/float(n)
44
45
46def sum_of_square_deviations(data, c):
47 """Return sum of square deviations of sequence data."""
48 ss = sum((float(x) - c)**2 for x in data)
49 return ss
50
51
52def coefficient_of_variation(data):
53 """Calculates the population coefficient of variation."""
54 n = len(data)
55 if n < 2:
56 raise ValueError('variance requires at least two data points')
57 c = mean(data)
58 ss = sum_of_square_deviations(data, c)
59 pvar = ss / n # the population variance
60 stddev = (pvar**0.5) # population standard deviation
61 return stddev / c
62
63
64def truncated_list(data, n):
65 """Compute a truncated list, n is truncation size"""
66 if len(data) < n * 2:
67 raise ValueError('list not large enough to truncate')
68 return sorted(data)[n:-n]
69
70
71def truncated_mean(data, n):
72 """Compute a truncated mean, n is truncation size"""
73 return mean(truncated_list(data, n))
74
75
76def truncated_cov(data, n):
77 """Compute a truncated coefficient of variation, n is truncation size"""
78 return coefficient_of_variation(truncated_list(data, n))
79
80
81# Find most recent binary
82newest_binary = None
83newest_mtime = None
84
85for path in perftests_paths:
86 binary_path = os.path.join(base_path, path, binary_name)
87 if os.path.exists(binary_path):
88 binary_mtime = os.path.getmtime(binary_path)
89 if (newest_binary is None) or (binary_mtime > newest_mtime):
90 newest_binary = binary_path
91 newest_mtime = binary_mtime
92
93perftests_path = newest_binary
94
95if perftests_path == None or not os.path.exists(perftests_path):
96 print('Cannot find Release %s!' % binary_name)
97 sys.exit(1)
98
99if len(sys.argv) >= 2:
100 test_name = sys.argv[1]
101
102print('Using test executable: ' + perftests_path)
103print('Test name: ' + test_name)
104
105def get_results(metric, extra_args=[]):
106 process = subprocess.Popen(
107 [perftests_path, '--gtest_filter=' + test_name] + extra_args,
108 stdout=subprocess.PIPE,
109 stderr=subprocess.PIPE)
110 output, err = process.communicate()
111
112 m = re.search(r'Running (\d+) tests', output)
113 if m and int(m.group(1)) > 1:
114 print("Found more than one test result in output:")
115 print(output)
116 sys.exit(3)
117
Bryan Bernhart4b1be082020-03-26 17:46:25 +0000118 pattern = metric + r'.*= ([0-9.]+)'
Austin Engca0eac32019-08-28 23:18:10 +0000119 m = re.findall(pattern, output)
Bryan Bernhart4b1be082020-03-26 17:46:25 +0000120 if not m:
Austin Engca0eac32019-08-28 23:18:10 +0000121 print("Did not find the metric '%s' in the test output:" % metric)
122 print(output)
123 sys.exit(1)
124
125 return [float(value) for value in m]
126
127
128# Calibrate the number of steps
129steps = get_results("steps", ["--calibration"])[0]
130print("running with %d steps." % steps)
131
132# Loop 'max_experiments' times, running the tests.
133for experiment in range(max_experiments):
134 experiment_scores = get_results(metric, ["--override-steps", str(steps)])
135
136 for score in experiment_scores:
137 sys.stdout.write("%s: %.2f" % (metric, score))
138 scores.append(score)
139
140 if (len(scores) > 1):
141 sys.stdout.write(", mean: %.2f" % mean(scores))
142 sys.stdout.write(", variation: %.2f%%" % (coefficient_of_variation(scores) * 100.0))
143
144 if (len(scores) > 7):
145 truncation_n = len(scores) >> 3
146 sys.stdout.write(", truncated mean: %.2f" % truncated_mean(scores, truncation_n))
147 sys.stdout.write(", variation: %.2f%%" % (truncated_cov(scores, truncation_n) * 100.0))
148
149 print("")