Index: tools/testing/perf_testing/run_perf_tests.py |
=================================================================== |
--- tools/testing/perf_testing/run_perf_tests.py (revision 10085) |
+++ tools/testing/perf_testing/run_perf_tests.py (working copy) |
@@ -6,14 +6,10 @@ |
import datetime |
import math |
-try: |
- from matplotlib.font_manager import FontProperties |
- import matplotlib.pyplot as plt |
-except ImportError: |
- pass # Only needed if we want to make graphs. |
import optparse |
import os |
from os.path import dirname, abspath |
+import pickle |
import platform |
import re |
import shutil |
@@ -67,12 +63,12 @@ |
out.seek(0, os.SEEK_END) |
p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE, |
stdin=subprocess.PIPE, shell=self.has_shell) |
- output, stderr = p.communicate(std_in); |
+ output, stderr = p.communicate(std_in) |
if output: |
print output |
if stderr: |
print stderr |
- return output |
+ return output, stderr |
def time_cmd(self, cmd): |
"""Determine the amount of (real) time it takes to execute a given |
@@ -81,21 +77,7 @@ |
self.run_cmd(cmd) |
return time.time() - start |
- @staticmethod |
- def get_build_targets(suites): |
- """Loop through a set of tests that we want to run and find the build |
- targets that are necessary. |
- |
- Args: |
- suites: The test suites that we wish to run.""" |
- build_targets = set() |
- for test in suites: |
- if test.build_targets is not None: |
- for target in test.build_targets: |
- build_targets.add(target) |
- return build_targets |
- |
- def sync_and_build(self, suites): |
+ def sync_and_build(self, suites, revision_num=''): |
"""Make sure we have the latest version of of the repo, and build it. We |
begin and end standing in DART_INSTALL_LOCATION. |
@@ -105,37 +87,20 @@ |
Returns: |
err_code = 1 if there was a problem building.""" |
os.chdir(DART_INSTALL_LOCATION) |
+ |
+ if revision_num == '': |
+ self.run_cmd(['gclient', 'sync']) |
+ else: |
+ self.run_cmd(['gclient', 'sync', '-r', revision_num, '-t']) |
- self.run_cmd(['gclient', 'sync']) |
- |
- # On Windows, the output directory is marked as "Read Only," which causes an |
- # error to be thrown when we use shutil.rmtree. This helper function changes |
- # the permissions so we can still delete the directory. |
- def on_rm_error(func, path, exc_info): |
- if os.path.exists(path): |
- os.chmod(path, stat.S_IWRITE) |
- os.unlink(path) |
- # TODO(efortuna): building the sdk locally is a band-aid until all build |
- # platform SDKs are hosted in Google storage. Pull from https://sandbox. |
- # google.com/storage/?arg=dart-dump-render-tree/sdk/#dart-dump-render-tree |
- # %2Fsdk eventually. |
- # TODO(efortuna): Currently always building ia32 architecture because we |
- # don't have test statistics for what's passing on x64. Eliminate arch |
- # specification when we have tests running on x64, too. |
- shutil.rmtree(os.path.join(os.getcwd(), |
- utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32')), |
- onerror=on_rm_error) |
- |
- for target in TestRunner.get_build_targets(suites): |
- lines = self.run_cmd([os.path.join('.', 'tools', 'build.py'), '-m', |
- 'release', '--arch=ia32', target]) |
- |
- for line in lines: |
- if 'BUILD FAILED' in lines: |
- # Someone checked in a broken build! Stop trying to make it work |
- # and wait to try again. |
- print 'Broken Build' |
- return 1 |
+ if revision_num == '': |
+ revision_num = search_for_revision(['svn', 'info']) |
+ if revision_num == -1: |
+ revision_num = search_for_revision(['git', 'svn', 'info']) |
+ _, stderr = self.run_cmd(['python', os.path.join(DART_INSTALL_LOCATION, |
+ 'tools', 'get_archive.py'), 'sdk', '-r', revision_num]) |
+ if 'InvalidUriError' in stderr: |
+ return 1 |
return 0 |
def ensure_output_directory(self, dir_name): |
@@ -155,7 +120,7 @@ |
os.chdir(DART_INSTALL_LOCATION) |
# Pass 'p' in if we have a new certificate for the svn server, we want to |
# (p)ermanently accept it. |
- results = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') |
+ results, _ = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') |
for line in results: |
if '*' in line: |
return True |
@@ -211,29 +176,36 @@ |
self.verbose = args.verbose |
return args.continuous |
- def run_test_sequence(self): |
- """Run the set of commands to (possibly) build, run, and graph the results |
- of our tests. |
+ def run_test_sequence(self, revision_num='', num_reruns=1): |
+ """Run the set of commands to (possibly) build, run, and post the results |
+ of our tests. Returns 0 on a successful run, 1 if we fail to post results or |
+ the run failed, -1 if the build is broken. |
""" |
suites = [] |
+ success = True |
for name in self.suite_names: |
- suites += [TestBuilder.make_test(name, self)] |
+ for run in range(num_reruns): |
+ suites += [TestBuilder.make_test(name, self)] |
- if not self.no_build and self.sync_and_build(suites) == 1: |
- return # The build is broken. |
+ if not self.no_build and self.sync_and_build(suites, revision_num) == 1: |
+ return -1 # The build is broken. |
for test in suites: |
- test.run() |
+ success = success and test.run() |
+ if success: |
+ return 0 |
+ else: |
+ return 1 |
class Test(object): |
"""The base class to provide shared code for different tests we will run and |
- graph. At a high level, each test has three visitors (the tester, the |
- file_processor and the grapher) that perform operations on the test object.""" |
+ post. At a high level, each test has three visitors (the tester and the |
+ file_processor) that perform operations on the test object.""" |
def __init__(self, result_folder_name, platform_list, variants, |
- values_list, test_runner, tester, file_processor, grapher, |
- extra_metrics=['Geo-Mean'], build_targets=['create_sdk']): |
+ values_list, test_runner, tester, file_processor, |
+ extra_metrics=['Geo-Mean']): |
"""Args: |
result_folder_name: The name of the folder where a tracefile of |
performance results will be stored. |
@@ -249,11 +221,8 @@ |
tester: The visitor that actually performs the test running mechanics. |
file_processor: The visitor that processes files in the format |
appropriate for this test. |
- grapher: The visitor that generates graphs given our test result data. |
extra_metrics: A list of any additional measurements we wish to keep |
- track of (such as the geometric mean of a set, the sum, etc). |
- build_targets: The targets necessary to build to run these tests |
- (default target is create_sdk).""" |
+ track of (such as the geometric mean of a set, the sum, etc).""" |
self.result_folder_name = result_folder_name |
# cur_time is used as a timestamp of when this performance test was run. |
self.cur_time = str(time.mktime(datetime.datetime.now().timetuple())) |
@@ -262,10 +231,8 @@ |
self.test_runner = test_runner |
self.tester = tester |
self.file_processor = file_processor |
- self.build_targets = build_targets |
self.revision_dict = dict() |
self.values_dict = dict() |
- self.grapher = grapher |
self.extra_metrics = extra_metrics |
# Initialize our values store. |
for platform in platform_list: |
@@ -291,7 +258,7 @@ |
"""Run the benchmarks/tests from the command line and plot the |
results. |
""" |
- for visitor in [self.tester, self.file_processor, self.grapher]: |
+ for visitor in [self.tester, self.file_processor]: |
visitor.prepare() |
os.chdir(DART_INSTALL_LOCATION) |
@@ -308,16 +275,17 @@ |
self.file_processor.process_file(afile, False) |
files = os.listdir(self.result_folder_name) |
+ post_success = True |
for afile in files: |
if not afile.startswith('.'): |
should_move_file = self.file_processor.process_file(afile, True) |
if should_move_file: |
shutil.move(os.path.join(self.result_folder_name, afile), |
os.path.join('old', self.result_folder_name, afile)) |
+ else: |
+ post_success = False |
- if 'plt' in globals(): |
- # Only run Matplotlib if it is installed. |
- self.grapher.plot_results('%s.png' % self.result_folder_name) |
+ return post_success |
class Tester(object): |
@@ -334,17 +302,6 @@ |
def add_svn_revision_to_trace(self, outfile, browser = None): |
"""Add the svn version number to the provided tracefile.""" |
- def search_for_revision(svn_info_command): |
- p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE, |
- stderr = subprocess.STDOUT, shell = |
- self.test.test_runner.has_shell) |
- output, _ = p.communicate() |
- for line in output.split('\n'): |
- if 'Revision' in line: |
- self.test.test_runner.run_cmd(['echo', line.strip()], outfile) |
- return True |
- return False |
- |
def get_dartium_revision(): |
version_file_name = os.path.join(DART_INSTALL_LOCATION, 'client', 'tests', |
'dartium', 'LAST_VERSION') |
@@ -356,9 +313,11 @@ |
if browser and browser == 'dartium': |
revision = get_dartium_revision() |
self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile) |
- elif not search_for_revision(['svn', 'info']): |
- if not search_for_revision(['git', 'svn', 'info']): |
- self.test.test_runner.run_cmd(['echo', 'Revision: unknown'], outfile) |
+ else: |
+ revision = search_for_revision(['svn', 'info']) |
+ if revision == -1: |
+ revision = search_for_revision(['git', 'svn', 'info']) |
+ self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile) |
class Processor(object): |
@@ -409,8 +368,6 @@ |
"""Calculate the aggregate geometric mean for JS and frog benchmark sets, |
given two benchmark dictionaries.""" |
geo_mean = 0 |
- # TODO(vsm): Suppress graphing this combination altogether. For |
- # now, we feed a geomean of 0. |
if self.test.is_valid_combination(platform, variant): |
for benchmark in self.test.values_list: |
geo_mean += math.log( |
@@ -420,92 +377,18 @@ |
self.test.values_dict[platform][variant]['Geo-Mean'] += \ |
[math.pow(math.e, geo_mean / len(self.test.values_list))] |
self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] |
- |
- |
-class Grapher(object): |
- """The base level visitor class that generates graphs for data. It contains |
- convenience methods that many Grapher objects use. Any class that would like |
- to be a GrapherVisitor must implement the plot_results() method.""" |
- graph_out_dir = 'graphs' |
+ def get_score_type(self, benchmark_name): |
+ """Determine the type of score for posting -- default is 'Score' (aka |
+ Runtime), other options are CompileTime and CodeSize.""" |
+ return self.SCORE |
- def __init__(self, test): |
- self.color_index = 0 |
- self.test = test |
- def prepare(self): |
- """Perform any initial setup required before the test is run.""" |
- if 'plt' in globals(): |
- plt.cla() # cla = clear current axes |
- else: |
- print 'Unable to import Matplotlib and therefore unable to generate ' + \ |
- 'graphs. Please install it for this version of Python.' |
- self.test.test_runner.ensure_output_directory(Grapher.graph_out_dir) |
- |
- def style_and_save_perf_plot(self, chart_title, y_axis_label, size_x, size_y, |
- legend_loc, filename, platform_list, variants, |
- values_list, should_clear_axes=True): |
- """Sets style preferences for chart boilerplate that is consistent across |
- all charts, and saves the chart as a png. |
- Args: |
- size_x: the size of the printed chart, in inches, in the horizontal |
- direction |
- size_y: the size of the printed chart, in inches in the vertical direction |
- legend_loc: the location of the legend in on the chart. See suitable |
- arguments for the loc argument in matplotlib |
- filename: the filename that we want to save the resulting chart as |
- platform_list: a list containing the platform(s) that our data has been |
- run on. (command line, firefox, chrome, etc) |
- values_list: a list containing the type of data we will be graphing |
- (performance, percentage passing, etc) |
- should_clear_axes: True if we want to create a fresh graph, instead of |
- plotting additional lines on the current graph.""" |
- if should_clear_axes: |
- plt.cla() # cla = clear current axes |
- for platform in platform_list: |
- for f in variants: |
- for val in values_list: |
- plt.plot(self.test.revision_dict[platform][f][val], |
- self.test.values_dict[platform][f][val], |
- color=self.get_color(), label='%s-%s-%s' % (platform, f, val)) |
- |
- plt.xlabel('Revision Number') |
- plt.ylabel(y_axis_label) |
- plt.title(chart_title) |
- fontP = FontProperties() |
- fontP.set_size('small') |
- plt.legend(loc=legend_loc, prop = fontP) |
- |
- fig = plt.gcf() |
- fig.set_size_inches(size_x, size_y) |
- fig.savefig(os.path.join(Grapher.graph_out_dir, filename)) |
- |
- def get_color(self): |
- # Just a bunch of distinct colors for a potentially large number of values |
- # we wish to graph. |
- colors = [ |
- 'blue', 'green', 'red', 'cyan', 'magenta', 'black', '#3366CC', |
- '#DC3912', '#FF9900', '#109618', '#990099', '#0099C6', '#DD4477', |
- '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11', |
- '#6633CC', '#E67300', '#8B0707', '#651067', '#329262', '#5574A6', |
- '#3B3EAC', '#B77322', '#16D620', '#B91383', '#F4359E', '#9C5935', |
- '#A9C413', '#2A778D', '#668D1C', '#BEA413', '#0C5922', '#743411', |
- '#45AFE2', '#FF3300', '#FFCC00', '#14C21D', '#DF51FD', '#15CBFF', |
- '#FF97D2', '#97FB00', '#DB6651', '#518BC6', '#BD6CBD', '#35D7C2', |
- '#E9E91F', '#9877DD', '#FF8F20', '#D20B0B', '#B61DBA', '#40BD7E', |
- '#6AA7C4', '#6D70CD', '#DA9136', '#2DEA36', '#E81EA6', '#F558AE', |
- '#C07145', '#D7EE53', '#3EA7C6', '#97D129', '#E9CA1D', '#149638', |
- '#C5571D'] |
- color = colors[self.color_index] |
- self.color_index = (self.color_index + 1) % len(colors) |
- return color |
- |
class RuntimePerformanceTest(Test): |
"""Super class for all runtime performance testing.""" |
def __init__(self, result_folder_name, platform_list, platform_type, |
- versions, benchmarks, test_runner, tester, file_processor, |
- build_targets=['create_sdk']): |
+ versions, benchmarks, test_runner, tester, file_processor): |
"""Args: |
result_folder_name: The name of the folder where a tracefile of |
performance results will be stored. |
@@ -521,57 +404,17 @@ |
tester: The visitor that actually performs the test running mechanics. |
file_processor: The visitor that processes files in the format |
appropriate for this test. |
- grapher: The visitor that generates graphs given our test result data. |
extra_metrics: A list of any additional measurements we wish to keep |
- track of (such as the geometric mean of a set, the sum, etc). |
- build_targets: The targets necessary to build to run these tests |
- (default target is create_sdk).""" |
+ track of (such as the geometric mean of a set, the sum, etc).""" |
super(RuntimePerformanceTest, self).__init__(result_folder_name, |
platform_list, versions, benchmarks, test_runner, tester, |
- file_processor, RuntimePerfGrapher(self), |
- build_targets=build_targets) |
+ file_processor) |
self.platform_list = platform_list |
self.platform_type = platform_type |
self.versions = versions |
self.benchmarks = benchmarks |
-class RuntimePerfGrapher(Grapher): |
- def plot_all_perf(self, png_filename): |
- """Create a plot that shows the performance changes of individual |
- benchmarks run by JS and generated by frog, over svn history.""" |
- for benchmark in self.test.benchmarks: |
- self.style_and_save_perf_plot( |
- 'Performance of %s over time on the %s on %s' % (benchmark, |
- self.test.platform_type, utils.GuessOS()), |
- 'Speed (bigger = better)', 16, 14, 'lower left', |
- benchmark + png_filename, self.test.platform_list, |
- self.test.versions, [benchmark]) |
- def plot_avg_perf(self, png_filename, platforms=None, versions=None): |
- """Generate a plot that shows the performance changes of the geomentric |
- mean of JS and frog benchmark performance over svn history.""" |
- if platforms == None: |
- platforms = self.test.platform_list |
- if versions == None: |
- versions = self.test.versions |
- (title, y_axis, size_x, size_y, loc, filename) = \ |
- ('Geometric Mean of benchmark %s performance on %s ' % |
- (self.test.platform_type, utils.GuessOS()), 'Speed (bigger = better)', |
- 16, 5, 'lower left', 'avg'+png_filename) |
- clear_axis = True |
- for platform in platforms: |
- for version in versions: |
- if self.test.is_valid_combination(platform, version): |
- for metric in self.test.extra_metrics: |
- self.style_and_save_perf_plot(title, y_axis, size_x, size_y, loc, |
- filename, [platform], [version], |
- [metric], clear_axis) |
- clear_axis = False |
- |
- def plot_results(self, png_filename): |
- self.plot_all_perf(png_filename) |
- self.plot_avg_perf('2' + png_filename) |
- |
class BrowserTester(Tester): |
@staticmethod |
def get_browsers(add_dartium=True): |
@@ -587,8 +430,8 @@ |
if 'dartium' in browsers: |
# Fetch it if necessary. |
get_dartium = ['python', |
- os.path.join(DART_INSTALL_LOCATION, 'tools', 'get_drt.py'), |
- '--dartium'] |
+ os.path.join(DART_INSTALL_LOCATION, 'tools', |
+ 'get_archive.py'), 'dartium'] |
# TODO(vsm): It's inconvenient that run_cmd isn't in scope here. |
# Perhaps there is a better place to put that or this. |
subprocess.call(get_dartium, stdout=sys.stdout, stderr=sys.stderr, |
@@ -624,10 +467,9 @@ |
class CommonBrowserTester(BrowserTester): |
def run_tests(self): |
"""Run a performance test in the browser.""" |
- os.chdir('frog') |
- self.test.test_runner.run_cmd(['python', os.path.join('benchmarks', |
- 'make_web_benchmarks.py')]) |
- os.chdir('..') |
+ self.test.test_runner.run_cmd([ |
+ 'python', os.path.join('internal', 'browserBenchmarks', |
+ 'make_web_benchmarks.py')]) |
for browser in self.test.platform_list: |
for version in self.test.versions: |
@@ -647,6 +489,7 @@ |
append=True) |
class CommonBrowserFileProcessor(Processor): |
+ |
def process_file(self, afile, should_post_file): |
"""Comb through the html to find the performance results. |
Returns: True if we successfully posted our data to storage and/or we can |
@@ -694,7 +537,8 @@ |
self.test.revision_dict[browser][version][name] += [revision_num] |
if not self.test.test_runner.no_upload and should_post_file: |
upload_success = upload_success and self.report_results( |
- name, score, browser, version, revision_num, self.SCORE) |
+ name, score, browser, version, revision_num, |
+ self.get_score_type(name)) |
else: |
upload_success = False |
@@ -778,15 +622,12 @@ |
def __init__(self, test_runner): |
super(DromaeoTest, self).__init__( |
self.name(), |
- filter(lambda x: x != 'ie', BrowserTester.get_browsers()), |
+ BrowserTester.get_browsers(), |
'browser', |
DromaeoTester.get_dromaeo_versions(), |
DromaeoTester.get_dromaeo_benchmarks(), test_runner, |
self.DromaeoPerfTester(self), |
self.DromaeoFileProcessor(self)) |
- # TODO(vsm): These tester/grapher/processor classes should be |
- # cleaner to override. |
- self.grapher = self.DromaeoPerfGrapher(self) |
@staticmethod |
def name(): |
@@ -800,24 +641,8 @@ |
# dart:dom has been removed from Dartium. |
if browser == 'dartium' and 'dom' in version: |
return False |
- if browser == 'ff': |
- # TODO(vsm): We are waiting on a fix from Issue 3152 from dart2js. |
- return False |
return True |
- class DromaeoPerfGrapher(RuntimePerfGrapher): |
- def plot_results(self, png_filename): |
- self.plot_all_perf(png_filename) |
- self.plot_avg_perf('2' + png_filename) |
- self.plot_avg_perf('3' + png_filename, ['chrome', 'dartium'], |
- ['js', 'frog_dom', 'frog_html']) |
- self.plot_avg_perf('4' + png_filename, ['chrome'], |
- ['js', 'frog_dom', 'dart2js_dom']) |
- self.plot_avg_perf('5' + png_filename, ['chrome'], |
- ['js', 'dart2js_dom', 'dart2js_html']) |
- self.plot_avg_perf('6' + png_filename, ['chrome'], |
- ['js', 'frog_dom', 'frog_html', 'dart2js_dom', |
- 'dart2js_html']) |
class DromaeoPerfTester(DromaeoTester): |
def move_chrome_driver_if_needed(self, browser): |
@@ -832,7 +657,7 @@ |
current_dir = os.getcwd() |
os.chdir(DART_INSTALL_LOCATION) |
self.test.test_runner.run_cmd(['python', os.path.join( |
- 'tools', 'get_drt.py'), '--chromedriver']) |
+ 'tools', 'get_archive.py'), 'chromedriver']) |
path = os.environ['PATH'].split(os.pathsep) |
orig_chromedriver_path = os.path.join('tools', 'testing', |
'orig-chromedriver') |
@@ -868,7 +693,7 @@ |
elif browser == 'dartium': |
if not os.path.exists(dartium_chromedriver_path): |
self.test.test_runner.run_cmd(['python', |
- os.path.join('tools', 'get_drt.py'), '--chromedriver']) |
+ os.path.join('tools', 'get_archive.py'), 'chromedriver']) |
# Move original chromedriver for storage. |
if not os.path.exists(orig_chromedriver_path): |
move_chromedriver(loc, copy_to_depot_tools_dir=False) |
@@ -958,7 +783,8 @@ |
[revision_num] |
if not self.test.test_runner.no_upload and should_post_file: |
upload_success = upload_success and self.report_results( |
- name, score, browser, version, revision_num, self.SCORE) |
+ name, score, browser, version, revision_num, |
+ self.get_score_type(name)) |
else: |
upload_success = False |
@@ -976,8 +802,7 @@ |
'frog_htmlidiomatic'], |
DromaeoTester.DROMAEO_BENCHMARKS.keys(), test_runner, |
self.DromaeoSizeTester(self), |
- self.DromaeoSizeProcessor(self), |
- self.DromaeoSizeGrapher(self), extra_metrics=['sum']) |
+ self.DromaeoSizeProcessor(self), extra_metrics=['sum']) |
@staticmethod |
def name(): |
@@ -1085,29 +910,17 @@ |
if not self.test.test_runner.no_upload and should_post_file: |
upload_success = upload_success and self.report_results( |
metric, num, 'commandline', variant, revision_num, |
- self.CODE_SIZE) |
+ self.get_score_type(metric)) |
else: |
upload_success = False |
f.close() |
return upload_success |
+ |
+ def get_score_type(self, metric): |
+ return self.CODE_SIZE |
- class DromaeoSizeGrapher(Grapher): |
- def plot_results(self, png_filename): |
- self.style_and_save_perf_plot( |
- 'Compiled Dromaeo Sizes', |
- 'Size (in bytes)', 10, 10, 'lower left', png_filename, |
- ['commandline'], |
- ['dart', 'frog_dom', 'frog_html', 'frog_htmlidiomatic'], |
- DromaeoTester.DROMAEO_BENCHMARKS.keys()) |
- self.style_and_save_perf_plot( |
- 'Compiled Dromaeo Sizes', |
- 'Size (in bytes)', 10, 10, 'lower left', '2' + png_filename, |
- ['commandline'], |
- ['dart', 'frog_dom', 'frog_html', 'frog_htmlidiomatic'], |
- [self.test.extra_metrics[0]]) |
- |
class CompileTimeAndSizeTest(Test): |
"""Run tests to determine how long frogc takes to compile, and the compiled |
file output size of some benchmarking files. |
@@ -1119,7 +932,7 @@ |
super(CompileTimeAndSizeTest, self).__init__( |
self.name(), ['commandline'], ['frog'], ['swarm', 'total'], |
test_runner, self.CompileTester(self), |
- self.CompileProcessor(self), self.CompileGrapher(self)) |
+ self.CompileProcessor(self)) |
self.dart_compiler = os.path.join( |
DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(), |
'release', 'ia32'), 'dart-sdk', 'bin', 'frogc') |
@@ -1197,9 +1010,7 @@ |
self.test.values_dict['commandline']['frog'][metric] += [num] |
self.test.revision_dict['commandline']['frog'][metric] += \ |
[revision_num] |
- score_type = self.CODE_SIZE |
- if 'Compiling' in metric or 'Bootstrapping' in metric: |
- score_type = self.COMPILE_TIME |
+ score_type = self.get_score_type(metric) |
if not self.test.test_runner.no_upload and should_post_file: |
if num < self.test.failure_threshold[metric]: |
num = 0 |
@@ -1228,14 +1039,11 @@ |
f.close() |
return upload_success |
- class CompileGrapher(Grapher): |
+ def get_score_type(self, metric): |
+ if 'Compiling' in metric or 'Bootstrapping' in metric: |
+ return self.COMPILE_TIME |
+ return self.CODE_SIZE |
- def plot_results(self, png_filename): |
- self.style_and_save_perf_plot( |
- 'Compiled frog sizes', 'Size (in bytes)', 10, 10, 'lower left', |
- png_filename, ['commandline'], ['frog'], ['swarm', 'total']) |
- |
- |
class TestBuilder(object): |
"""Construct the desired test object.""" |
available_suites = dict((suite.name(), suite) for suite in [ |
@@ -1249,15 +1057,76 @@ |
def available_suite_names(): |
return TestBuilder.available_suites.keys() |
+def search_for_revision(svn_info_command): |
+ p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE, |
+ stderr = subprocess.STDOUT, |
+ shell = (platform.system() == 'Windows')) |
+ output, _ = p.communicate() |
+ for line in output.split('\n'): |
+ if 'Revision' in line: |
+ return line.split()[1] |
+ return -1 |
+def update_set_of_done_cls(revision_num=None): |
+ """Update the set of CLs that do not need additional performance runs. |
+ Args: |
+ revision_num: an additional number to be added to the 'done set' |
+ """ |
+ filename = os.path.join(dirname(abspath(__file__)), 'cached_results.txt') |
+ if not os.path.exists(filename): |
+ f = open(filename, 'w') |
+ results = set() |
+ pickle.dump(results, f) |
+ f.close() |
+ f = open(filename) |
+ result_set = pickle.load(f) |
+ if revision_num: |
+ f.seek(0) |
+ result_set.add(revision_num) |
+ pickle.dump(result_set, f) |
+ f.close() |
+ return result_set |
+ |
def main(): |
runner = TestRunner() |
continuous = runner.parse_args() |
if continuous: |
while True: |
+ results_set = update_set_of_done_cls() |
if runner.has_new_code(): |
runner.run_test_sequence() |
else: |
+ # Try to get up to 10 runs of each CL, starting with the most recent CL |
+ # that does not yet have 10 runs. But only perform a set of extra runs |
+ # at most 10 at a time (get all the extra runs for one CL) before |
+ # checking to see if new code has been checked in. |
+ has_run_extra = False |
+ revision_num = int(search_for_revision(['svn', 'info'])) |
+ if revision_num == -1: |
+ revision_num = int(search_for_revision(['git', 'svn', 'info'])) |
+ |
+ # No need to track the performance before revision 3000. That's way in |
+ # the past. |
+ while revision_num > 3000 and not has_run_extra: |
ricow1
2012/08/06 11:10:03
This will take us back in time really really slow,
Emily Fortuna
2012/08/06 17:39:34
Right, so when this was originally designed, I tho
|
+ if revision_num not in results_set: |
+ a_test = TestBuilder.make_test(runner.suite_names[0], runner) |
+ benchmark_name = a_test.values_list[0] |
+ platform_name = a_test.platform_list[0] |
+ variant = a_test.values_dict[platform_name].keys()[0] |
+ number_of_results = post_results.get_num_results(benchmark_name, |
+ platform_name, variant, revision_num, |
+ a_test.file_processor.get_score_type(benchmark_name)) |
+ if number_of_results < 10 and number_of_results >= 0: |
+ run = runner.run_test_sequence(revision_num=str(revision_num), |
+ num_reruns=(10-number_of_results)) |
+ if run == 0: |
+ has_run_extra = True |
+ results_set = update_set_of_done_cls(revision_num) |
+ elif run == -1: |
+ # This revision is a broken build. Don't try to run it again. |
+ results_set = update_set_of_done_cls(revision_num) |
+ revision_num -= 1 |
+ # No more extra back-runs to do (for now). Wait for new code. |
time.sleep(200) |
else: |
runner.run_test_sequence() |