blob: 87e5b5fa9b6a275abae0014322df64023c887a61 [file] [log] [blame]
Jamie Madilld6dfe672015-11-20 12:18:12 -05001#!/usr/bin/python
2#
3# Copyright 2015 The ANGLE Project Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6#
7# perf_test_runner.py:
8# Helper script for running and analyzing perftest results. Runs the
9# tests in an infinite batch, printing out the mean and standard
10# deviation of the population continuously.
11#
12
13import subprocess
14import sys
15import os
Olli Etuahod39f8932015-12-17 17:10:02 +020016import re
17
18base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
Jamie Madilld6dfe672015-11-20 12:18:12 -050019
20# You might have to re-order these to find the specific version you want.
Olli Etuahod39f8932015-12-17 17:10:02 +020021perftests_paths = [
Olli Etuaho1bf91112017-02-06 13:46:30 +000022 os.path.join('src', 'tests', 'Release_x64'),
23 os.path.join('src', 'tests', 'Release_Win32'),
Jamie Madill1fbc59f2016-02-24 15:25:51 -050024 os.path.join('out', 'Release_x64'),
Olli Etuahod39f8932015-12-17 17:10:02 +020025 os.path.join('out', 'Release'),
Jamie Madill1079bb22016-11-17 10:00:39 -080026 os.path.join('gyp', 'Release_x64'),
27 os.path.join('gyp', 'Release_Win32')
Olli Etuahod39f8932015-12-17 17:10:02 +020028]
Jamie Madilld6dfe672015-11-20 12:18:12 -050029metric = 'score'
30
Jamie Madille4857c72016-04-21 14:13:53 -040031# TODO(jmadill): Linux binaries
32binary_name = 'angle_perftests.exe'
33
Jamie Madilld6dfe672015-11-20 12:18:12 -050034scores = []
35
36# Danke to http://stackoverflow.com/a/27758326
37def mean(data):
38 """Return the sample arithmetic mean of data."""
39 n = len(data)
40 if n < 1:
41 raise ValueError('mean requires at least one data point')
42 return float(sum(data))/float(n) # in Python 2 use sum(data)/float(n)
43
44def _ss(data):
45 """Return sum of square deviations of sequence data."""
46 c = mean(data)
47 ss = sum((float(x)-c)**2 for x in data)
48 return ss
49
50def pstdev(data):
51 """Calculates the population standard deviation."""
52 n = len(data)
53 if n < 2:
54 raise ValueError('variance requires at least two data points')
55 ss = _ss(data)
56 pvar = ss/n # the population variance
57 return pvar**0.5
58
59def truncated_list(data, n):
60 """Compute a truncated list, n is truncation size"""
61 if len(data) < n * 2:
62 raise ValueError('list not large enough to truncate')
63 return sorted(data)[n:-n]
64
65def truncated_mean(data, n):
66 return mean(truncated_list(data, n))
67
68def truncated_stddev(data, n):
69 return pstdev(truncated_list(data, n))
70
Jamie Madille4857c72016-04-21 14:13:53 -040071# Find most recent binary
72newest_binary = None
73newest_mtime = None
Jamie Madilld6dfe672015-11-20 12:18:12 -050074
Jamie Madilld6dfe672015-11-20 12:18:12 -050075for path in perftests_paths:
Jamie Madille4857c72016-04-21 14:13:53 -040076 binary_path = os.path.join(base_path, path, binary_name)
Jamie Madille4857c72016-04-21 14:13:53 -040077 if os.path.exists(binary_path):
Jamie Madill1079bb22016-11-17 10:00:39 -080078 binary_mtime = os.path.getmtime(binary_path)
Jamie Madille4857c72016-04-21 14:13:53 -040079 if (newest_binary is None) or (binary_mtime > newest_mtime):
80 newest_binary = binary_path
81 newest_mtime = binary_mtime
82
83perftests_path = newest_binary
Jamie Madilld6dfe672015-11-20 12:18:12 -050084
Jamie Madill1079bb22016-11-17 10:00:39 -080085if perftests_path == None or not os.path.exists(perftests_path):
86 print("Cannot find Release angle_perftests.exe!")
Jamie Madilld6dfe672015-11-20 12:18:12 -050087 sys.exit(1)
88
89test_name = "DrawCallPerfBenchmark.Run/d3d11_null"
90
91if len(sys.argv) >= 2:
92 test_name = sys.argv[1]
93
Olli Etuaho967cb3b2015-12-17 18:37:16 +020094print('Using test executable: ' + perftests_path)
95print('Test name: ' + test_name)
96
Jamie Madilld6dfe672015-11-20 12:18:12 -050097# Infinite loop of running the tests.
98while True:
99 output = subprocess.check_output([perftests_path, '--gtest_filter=' + test_name])
100
101 start_index = output.find(metric + "=")
102 if start_index == -1:
Olli Etuahod39f8932015-12-17 17:10:02 +0200103 print("Did not find the score of the specified test in output:")
104 print(output)
Jamie Madilld6dfe672015-11-20 12:18:12 -0500105 sys.exit(1)
106
107 start_index += len(metric) + 2
108
109 end_index = output[start_index:].find(" ")
110 if end_index == -1:
Olli Etuahod39f8932015-12-17 17:10:02 +0200111 print("Error parsing output:")
112 print(output)
Jamie Madilld6dfe672015-11-20 12:18:12 -0500113 sys.exit(2)
114
Olli Etuahod39f8932015-12-17 17:10:02 +0200115 m = re.search('Running (\d+) tests', output)
116 if m and int(m.group(1)) > 1:
117 print("Found more than one test result in output:")
118 print(output)
119 sys.exit(3)
120
Jamie Madilld6dfe672015-11-20 12:18:12 -0500121 end_index += start_index
122
123 score = int(output[start_index:end_index])
124 sys.stdout.write("score: " + str(score))
125
126 scores.append(score)
127 sys.stdout.write(", mean: " + str(mean(scores)))
128
129 if (len(scores) > 1):
130 sys.stdout.write(", stddev: " + str(pstdev(scores)))
131
132 if (len(scores) > 7):
133 trucation_n = len(scores) >> 3
134 sys.stdout.write(", truncated mean: " + str(truncated_mean(scores, trucation_n)))
135 sys.stdout.write(", stddev: " + str(truncated_stddev(scores, trucation_n)))
136
137 print("")