| OLD | NEW | 
|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python | 
| 2 # Copyright 2014 the V8 project authors. All rights reserved. | 2 # Copyright 2014 the V8 project authors. All rights reserved. | 
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be | 
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. | 
| 5 | 5 | 
| 6 """ | 6 """ | 
| 7 Performance runner for d8. | 7 Performance runner for d8. | 
| 8 | 8 | 
| 9 Call e.g. with tools/run-perf.py --arch ia32 some_suite.json | 9 Call e.g. with tools/run-perf.py --arch ia32 some_suite.json | 
| 10 | 10 | 
| 11 The suite json format is expected to be: | 11 The suite json format is expected to be: | 
| 12 { | 12 { | 
| 13   "path": <relative path chunks to perf resources and main file>, | 13   "path": <relative path chunks to perf resources and main file>, | 
| 14   "name": <optional suite name, file name is default>, | 14   "name": <optional suite name, file name is default>, | 
| 15   "archs": [<architecture name for which this suite is run>, ...], | 15   "archs": [<architecture name for which this suite is run>, ...], | 
| 16   "binary": <name of binary to run, default "d8">, | 16   "binary": <name of binary to run, default "d8">, | 
| 17   "flags": [<flag to d8>, ...], | 17   "flags": [<flag to d8>, ...], | 
|  | 18   "test_flags": [<flag to the test file>, ...], | 
| 18   "run_count": <how often will this suite run (optional)>, | 19   "run_count": <how often will this suite run (optional)>, | 
| 19   "run_count_XXX": <how often will this suite run for arch XXX (optional)>, | 20   "run_count_XXX": <how often will this suite run for arch XXX (optional)>, | 
| 20   "resources": [<js file to be loaded before main>, ...] | 21   "resources": [<js file to be loaded before main>, ...] | 
| 21   "main": <main js perf runner file>, | 22   "main": <main js perf runner file>, | 
| 22   "results_regexp": <optional regexp>, | 23   "results_regexp": <optional regexp>, | 
| 23   "results_processor": <optional python results processor script>, | 24   "results_processor": <optional python results processor script>, | 
| 24   "units": <the unit specification for the performance dashboard>, | 25   "units": <the unit specification for the performance dashboard>, | 
| 25   "tests": [ | 26   "tests": [ | 
| 26     { | 27     { | 
| 27       "name": <name of the trace>, | 28       "name": <name of the trace>, | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 47 | 48 | 
| 48 The <output> is a temporary file containing d8 output. The results_regexp will | 49 The <output> is a temporary file containing d8 output. The results_regexp will | 
| 49 be applied to the output of this script. | 50 be applied to the output of this script. | 
| 50 | 51 | 
| 51 A suite without "tests" is considered a performance test itself. | 52 A suite without "tests" is considered a performance test itself. | 
| 52 | 53 | 
| 53 Full example (suite with one runner): | 54 Full example (suite with one runner): | 
| 54 { | 55 { | 
| 55   "path": ["."], | 56   "path": ["."], | 
| 56   "flags": ["--expose-gc"], | 57   "flags": ["--expose-gc"], | 
|  | 58   "test_flags": ["5"], | 
| 57   "archs": ["ia32", "x64"], | 59   "archs": ["ia32", "x64"], | 
| 58   "run_count": 5, | 60   "run_count": 5, | 
| 59   "run_count_ia32": 3, | 61   "run_count_ia32": 3, | 
| 60   "main": "run.js", | 62   "main": "run.js", | 
| 61   "results_regexp": "^%s: (.+)$", | 63   "results_regexp": "^%s: (.+)$", | 
| 62   "units": "score", | 64   "units": "score", | 
| 63   "tests": [ | 65   "tests": [ | 
| 64     {"name": "Richards"}, | 66     {"name": "Richards"}, | 
| 65     {"name": "DeltaBlue"}, | 67     {"name": "DeltaBlue"}, | 
| 66     {"name": "NavierStokes", | 68     {"name": "NavierStokes", | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 82      "run_count": 3, | 84      "run_count": 3, | 
| 83      "results_regexp": "^Richards: (.+)$"}, | 85      "results_regexp": "^Richards: (.+)$"}, | 
| 84     {"name": "NavierStokes", | 86     {"name": "NavierStokes", | 
| 85      "path": ["navier_stokes"], | 87      "path": ["navier_stokes"], | 
| 86      "main": "run.js", | 88      "main": "run.js", | 
| 87      "results_regexp": "^NavierStokes: (.+)$"} | 89      "results_regexp": "^NavierStokes: (.+)$"} | 
| 88   ] | 90   ] | 
| 89 } | 91 } | 
| 90 | 92 | 
| 91 Path pieces are concatenated. D8 is always run with the suite's path as cwd. | 93 Path pieces are concatenated. D8 is always run with the suite's path as cwd. | 
|  | 94 | 
|  | 95 The test flags are passed to the js test file after '--'. | 
| 92 """ | 96 """ | 
| 93 | 97 | 
| 94 from collections import OrderedDict | 98 from collections import OrderedDict | 
| 95 import json | 99 import json | 
| 96 import math | 100 import math | 
| 97 import optparse | 101 import optparse | 
| 98 import os | 102 import os | 
| 99 import re | 103 import re | 
| 100 import sys | 104 import sys | 
| 101 | 105 | 
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 164 class DefaultSentinel(Node): | 168 class DefaultSentinel(Node): | 
| 165   """Fake parent node with all default values.""" | 169   """Fake parent node with all default values.""" | 
| 166   def __init__(self): | 170   def __init__(self): | 
| 167     super(DefaultSentinel, self).__init__() | 171     super(DefaultSentinel, self).__init__() | 
| 168     self.binary = "d8" | 172     self.binary = "d8" | 
| 169     self.run_count = 10 | 173     self.run_count = 10 | 
| 170     self.timeout = 60 | 174     self.timeout = 60 | 
| 171     self.path = [] | 175     self.path = [] | 
| 172     self.graphs = [] | 176     self.graphs = [] | 
| 173     self.flags = [] | 177     self.flags = [] | 
|  | 178     self.test_flags = [] | 
| 174     self.resources = [] | 179     self.resources = [] | 
| 175     self.results_regexp = None | 180     self.results_regexp = None | 
| 176     self.stddev_regexp = None | 181     self.stddev_regexp = None | 
| 177     self.units = "score" | 182     self.units = "score" | 
| 178     self.total = False | 183     self.total = False | 
| 179 | 184 | 
| 180 | 185 | 
| 181 class Graph(Node): | 186 class Graph(Node): | 
| 182   """Represents a suite definition. | 187   """Represents a suite definition. | 
| 183 | 188 | 
| 184   Can either be a leaf or an inner node that provides default values. | 189   Can either be a leaf or an inner node that provides default values. | 
| 185   """ | 190   """ | 
| 186   def __init__(self, suite, parent, arch): | 191   def __init__(self, suite, parent, arch): | 
| 187     super(Graph, self).__init__() | 192     super(Graph, self).__init__() | 
| 188     self._suite = suite | 193     self._suite = suite | 
| 189 | 194 | 
| 190     assert isinstance(suite.get("path", []), list) | 195     assert isinstance(suite.get("path", []), list) | 
| 191     assert isinstance(suite["name"], basestring) | 196     assert isinstance(suite["name"], basestring) | 
| 192     assert isinstance(suite.get("flags", []), list) | 197     assert isinstance(suite.get("flags", []), list) | 
|  | 198     assert isinstance(suite.get("test_flags", []), list) | 
| 193     assert isinstance(suite.get("resources", []), list) | 199     assert isinstance(suite.get("resources", []), list) | 
| 194 | 200 | 
| 195     # Accumulated values. | 201     # Accumulated values. | 
| 196     self.path = parent.path[:] + suite.get("path", []) | 202     self.path = parent.path[:] + suite.get("path", []) | 
| 197     self.graphs = parent.graphs[:] + [suite["name"]] | 203     self.graphs = parent.graphs[:] + [suite["name"]] | 
| 198     self.flags = parent.flags[:] + suite.get("flags", []) | 204     self.flags = parent.flags[:] + suite.get("flags", []) | 
|  | 205     self.test_flags = parent.test_flags[:] + suite.get("test_flags", []) | 
| 199     self.resources = parent.resources[:] + suite.get("resources", []) | 206     self.resources = parent.resources[:] + suite.get("resources", []) | 
| 200 | 207 | 
| 201     # Descrete values (with parent defaults). | 208     # Descrete values (with parent defaults). | 
| 202     self.binary = suite.get("binary", parent.binary) | 209     self.binary = suite.get("binary", parent.binary) | 
| 203     self.run_count = suite.get("run_count", parent.run_count) | 210     self.run_count = suite.get("run_count", parent.run_count) | 
| 204     self.run_count = suite.get("run_count_%s" % arch, self.run_count) | 211     self.run_count = suite.get("run_count_%s" % arch, self.run_count) | 
| 205     self.timeout = suite.get("timeout", parent.timeout) | 212     self.timeout = suite.get("timeout", parent.timeout) | 
| 206     self.units = suite.get("units", parent.units) | 213     self.units = suite.get("units", parent.units) | 
| 207     self.total = suite.get("total", parent.total) | 214     self.total = suite.get("total", parent.total) | 
| 208 | 215 | 
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 275     """Changes the cwd to to path defined in the current graph. | 282     """Changes the cwd to to path defined in the current graph. | 
| 276 | 283 | 
| 277     The tests are supposed to be relative to the suite configuration. | 284     The tests are supposed to be relative to the suite configuration. | 
| 278     """ | 285     """ | 
| 279     suite_dir = os.path.abspath(os.path.dirname(suite_path)) | 286     suite_dir = os.path.abspath(os.path.dirname(suite_path)) | 
| 280     bench_dir = os.path.normpath(os.path.join(*self.path)) | 287     bench_dir = os.path.normpath(os.path.join(*self.path)) | 
| 281     os.chdir(os.path.join(suite_dir, bench_dir)) | 288     os.chdir(os.path.join(suite_dir, bench_dir)) | 
| 282 | 289 | 
| 283   def GetCommand(self, shell_dir): | 290   def GetCommand(self, shell_dir): | 
| 284     # TODO(machenbach): This requires +.exe if run on windows. | 291     # TODO(machenbach): This requires +.exe if run on windows. | 
|  | 292     suffix = ["--"] + self.test_flags if self.test_flags else [] | 
| 285     return ( | 293     return ( | 
| 286       [os.path.join(shell_dir, self.binary)] + | 294       [os.path.join(shell_dir, self.binary)] + | 
| 287       self.flags + | 295       self.flags + | 
| 288       self.resources + | 296       self.resources + | 
| 289       [self.main] | 297       [self.main] + | 
|  | 298       suffix | 
| 290     ) | 299     ) | 
| 291 | 300 | 
| 292   def Run(self, runner): | 301   def Run(self, runner): | 
| 293     """Iterates over several runs and handles the output for all traces.""" | 302     """Iterates over several runs and handles the output for all traces.""" | 
| 294     for stdout in runner(): | 303     for stdout in runner(): | 
| 295       for trace in self._children: | 304       for trace in self._children: | 
| 296         trace.ConsumeOutput(stdout) | 305         trace.ConsumeOutput(stdout) | 
| 297     res = reduce(lambda r, t: r + t.GetResults(), self._children, Results()) | 306     res = reduce(lambda r, t: r + t.GetResults(), self._children, Results()) | 
| 298 | 307 | 
| 299     if not res.traces or not self.total: | 308     if not res.traces or not self.total: | 
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 499 | 508 | 
| 500   if options.json_test_results: | 509   if options.json_test_results: | 
| 501     results.WriteToFile(options.json_test_results) | 510     results.WriteToFile(options.json_test_results) | 
| 502   else:  # pragma: no cover | 511   else:  # pragma: no cover | 
| 503     print results | 512     print results | 
| 504 | 513 | 
| 505   return min(1, len(results.errors)) | 514   return min(1, len(results.errors)) | 
| 506 | 515 | 
| 507 if __name__ == "__main__":  # pragma: no cover | 516 if __name__ == "__main__":  # pragma: no cover | 
| 508   sys.exit(Main(sys.argv[1:])) | 517   sys.exit(Main(sys.argv[1:])) | 
| OLD | NEW | 
|---|