Jeff Gilbert | 1b605ee | 2017-10-30 18:41:46 -0700 | [diff] [blame] | 1 | #!/usr/bin/python2 |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 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 | |
| 13 | import subprocess |
| 14 | import sys |
| 15 | import os |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 16 | import re |
| 17 | |
| 18 | base_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')) |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 19 | |
| 20 | # You might have to re-order these to find the specific version you want. |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 21 | perftests_paths = [ |
Olli Etuaho | 1bf9111 | 2017-02-06 13:46:30 +0000 | [diff] [blame] | 22 | os.path.join('src', 'tests', 'Release_x64'), |
| 23 | os.path.join('src', 'tests', 'Release_Win32'), |
Jamie Madill | 1fbc59f | 2016-02-24 15:25:51 -0500 | [diff] [blame] | 24 | os.path.join('out', 'Release_x64'), |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 25 | os.path.join('out', 'Release'), |
Jamie Madill | 1079bb2 | 2016-11-17 10:00:39 -0800 | [diff] [blame] | 26 | os.path.join('gyp', 'Release_x64'), |
| 27 | os.path.join('gyp', 'Release_Win32') |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 28 | ] |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 29 | metric = 'score' |
| 30 | |
Shao | 29e9035 | 2017-05-05 16:41:29 +0800 | [diff] [blame] | 31 | binary_name = 'angle_perftests' |
| 32 | if sys.platform == 'win32': |
| 33 | binary_name += '.exe' |
Jamie Madill | e4857c7 | 2016-04-21 14:13:53 -0400 | [diff] [blame] | 34 | |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 35 | scores = [] |
| 36 | |
| 37 | # Danke to http://stackoverflow.com/a/27758326 |
| 38 | def 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 | def _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 | |
| 51 | def 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 | |
| 60 | def 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 | |
| 66 | def truncated_mean(data, n): |
| 67 | return mean(truncated_list(data, n)) |
| 68 | |
| 69 | def truncated_stddev(data, n): |
| 70 | return pstdev(truncated_list(data, n)) |
| 71 | |
Jamie Madill | e4857c7 | 2016-04-21 14:13:53 -0400 | [diff] [blame] | 72 | # Find most recent binary |
| 73 | newest_binary = None |
| 74 | newest_mtime = None |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 75 | |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 76 | for path in perftests_paths: |
Jamie Madill | e4857c7 | 2016-04-21 14:13:53 -0400 | [diff] [blame] | 77 | binary_path = os.path.join(base_path, path, binary_name) |
Jamie Madill | e4857c7 | 2016-04-21 14:13:53 -0400 | [diff] [blame] | 78 | if os.path.exists(binary_path): |
Jamie Madill | 1079bb2 | 2016-11-17 10:00:39 -0800 | [diff] [blame] | 79 | binary_mtime = os.path.getmtime(binary_path) |
Jamie Madill | e4857c7 | 2016-04-21 14:13:53 -0400 | [diff] [blame] | 80 | if (newest_binary is None) or (binary_mtime > newest_mtime): |
| 81 | newest_binary = binary_path |
| 82 | newest_mtime = binary_mtime |
| 83 | |
| 84 | perftests_path = newest_binary |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 85 | |
Jamie Madill | 1079bb2 | 2016-11-17 10:00:39 -0800 | [diff] [blame] | 86 | if perftests_path == None or not os.path.exists(perftests_path): |
Shao | 29e9035 | 2017-05-05 16:41:29 +0800 | [diff] [blame] | 87 | print('Cannot find Release %s!' % binary_name) |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 88 | sys.exit(1) |
| 89 | |
Shao | 29e9035 | 2017-05-05 16:41:29 +0800 | [diff] [blame] | 90 | if sys.platform == 'win32': |
| 91 | test_name = 'DrawCallPerfBenchmark.Run/d3d11_null' |
| 92 | else: |
| 93 | test_name = 'DrawCallPerfBenchmark.Run/gl' |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 94 | |
| 95 | if len(sys.argv) >= 2: |
| 96 | test_name = sys.argv[1] |
| 97 | |
Olli Etuaho | 967cb3b | 2015-12-17 18:37:16 +0200 | [diff] [blame] | 98 | print('Using test executable: ' + perftests_path) |
| 99 | print('Test name: ' + test_name) |
| 100 | |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 101 | # Infinite loop of running the tests. |
| 102 | while True: |
Jamie Madill | fa08cae | 2017-08-31 14:39:13 -0400 | [diff] [blame] | 103 | process = subprocess.Popen([perftests_path, '--gtest_filter=' + test_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 104 | output, err = process.communicate() |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 105 | |
| 106 | start_index = output.find(metric + "=") |
| 107 | if start_index == -1: |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 108 | print("Did not find the score of the specified test in output:") |
| 109 | print(output) |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 110 | sys.exit(1) |
| 111 | |
| 112 | start_index += len(metric) + 2 |
| 113 | |
| 114 | end_index = output[start_index:].find(" ") |
| 115 | if end_index == -1: |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 116 | print("Error parsing output:") |
| 117 | print(output) |
Jamie Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 118 | sys.exit(2) |
| 119 | |
Olli Etuaho | d39f893 | 2015-12-17 17:10:02 +0200 | [diff] [blame] | 120 | 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 Madill | d6dfe67 | 2015-11-20 12:18:12 -0500 | [diff] [blame] | 126 | 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("") |