blob: 001ec4fa7bb6b207d0a21de095eac07f0a701724 [file] [log] [blame]
Jeff Gilbert1b605ee2017-10-30 18:41:46 -07001#!/usr/bin/python2
Jamie Madilld6dfe672015-11-20 12:18:12 -05002#
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
Shao29e90352017-05-05 16:41:29 +080031binary_name = 'angle_perftests'
32if sys.platform == 'win32':
33 binary_name += '.exe'
Jamie Madille4857c72016-04-21 14:13:53 -040034
Jamie Madilld6dfe672015-11-20 12:18:12 -050035scores = []
36
37# Danke to http://stackoverflow.com/a/27758326
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
45def _ss(data):
46 """Return sum of square deviations of sequence data."""
47 c = mean(data)
48 ss = sum((float(x)-c)**2 for x in data)
49 return ss
50
51def pstdev(data):
52 """Calculates the population standard deviation."""
53 n = len(data)
54 if n < 2:
55 raise ValueError('variance requires at least two data points')
56 ss = _ss(data)
57 pvar = ss/n # the population variance
58 return pvar**0.5
59
60def truncated_list(data, n):
61 """Compute a truncated list, n is truncation size"""
62 if len(data) < n * 2:
63 raise ValueError('list not large enough to truncate')
64 return sorted(data)[n:-n]
65
66def truncated_mean(data, n):
67 return mean(truncated_list(data, n))
68
69def truncated_stddev(data, n):
70 return pstdev(truncated_list(data, n))
71
Jamie Madille4857c72016-04-21 14:13:53 -040072# Find most recent binary
73newest_binary = None
74newest_mtime = None
Jamie Madilld6dfe672015-11-20 12:18:12 -050075
Jamie Madilld6dfe672015-11-20 12:18:12 -050076for path in perftests_paths:
Jamie Madille4857c72016-04-21 14:13:53 -040077 binary_path = os.path.join(base_path, path, binary_name)
Jamie Madille4857c72016-04-21 14:13:53 -040078 if os.path.exists(binary_path):
Jamie Madill1079bb22016-11-17 10:00:39 -080079 binary_mtime = os.path.getmtime(binary_path)
Jamie Madille4857c72016-04-21 14:13:53 -040080 if (newest_binary is None) or (binary_mtime > newest_mtime):
81 newest_binary = binary_path
82 newest_mtime = binary_mtime
83
84perftests_path = newest_binary
Jamie Madilld6dfe672015-11-20 12:18:12 -050085
Jamie Madill1079bb22016-11-17 10:00:39 -080086if perftests_path == None or not os.path.exists(perftests_path):
Shao29e90352017-05-05 16:41:29 +080087 print('Cannot find Release %s!' % binary_name)
Jamie Madilld6dfe672015-11-20 12:18:12 -050088 sys.exit(1)
89
Shao29e90352017-05-05 16:41:29 +080090if sys.platform == 'win32':
91 test_name = 'DrawCallPerfBenchmark.Run/d3d11_null'
92else:
93 test_name = 'DrawCallPerfBenchmark.Run/gl'
Jamie Madilld6dfe672015-11-20 12:18:12 -050094
95if len(sys.argv) >= 2:
96 test_name = sys.argv[1]
97
Olli Etuaho967cb3b2015-12-17 18:37:16 +020098print('Using test executable: ' + perftests_path)
99print('Test name: ' + test_name)
100
Jamie Madilld6dfe672015-11-20 12:18:12 -0500101# Infinite loop of running the tests.
102while True:
Jamie Madillfa08cae2017-08-31 14:39:13 -0400103 process = subprocess.Popen([perftests_path, '--gtest_filter=' + test_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
104 output, err = process.communicate()
Jamie Madilld6dfe672015-11-20 12:18:12 -0500105
106 start_index = output.find(metric + "=")
107 if start_index == -1:
Olli Etuahod39f8932015-12-17 17:10:02 +0200108 print("Did not find the score of the specified test in output:")
109 print(output)
Jamie Madilld6dfe672015-11-20 12:18:12 -0500110 sys.exit(1)
111
112 start_index += len(metric) + 2
113
114 end_index = output[start_index:].find(" ")
115 if end_index == -1:
Olli Etuahod39f8932015-12-17 17:10:02 +0200116 print("Error parsing output:")
117 print(output)
Jamie Madilld6dfe672015-11-20 12:18:12 -0500118 sys.exit(2)
119
Olli Etuahod39f8932015-12-17 17:10:02 +0200120 m = re.search('Running (\d+) tests', output)
121 if m and int(m.group(1)) > 1:
122 print("Found more than one test result in output:")
123 print(output)
124 sys.exit(3)
125
Jamie Madilld6dfe672015-11-20 12:18:12 -0500126 end_index += start_index
127
128 score = int(output[start_index:end_index])
129 sys.stdout.write("score: " + str(score))
130
131 scores.append(score)
132 sys.stdout.write(", mean: " + str(mean(scores)))
133
134 if (len(scores) > 1):
135 sys.stdout.write(", stddev: " + str(pstdev(scores)))
136
137 if (len(scores) > 7):
138 trucation_n = len(scores) >> 3
139 sys.stdout.write(", truncated mean: " + str(truncated_mean(scores, trucation_n)))
140 sys.stdout.write(", stddev: " + str(truncated_stddev(scores, trucation_n)))
141
142 print("")