Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1304)

Side by Side Diff: scripts/slave/recipe_modules/auto_bisect/perf_revision_state.py

Issue 940123005: Adding ability to bisect recipe to bisect into dependency repos. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@hax
Patch Set: Missing docstring Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import json 5 import json
6 import tempfile
7 import os
6 import uuid 8 import uuid
7 9
8 from . import revision_state 10 from . import revision_state
9 11
12 if 'CACHE_TEST_RESULTS' in os.environ: # pragma: no cover
13 from . import test_results_cache
14
10 15
11 class PerfRevisionState(revision_state.RevisionState): 16 class PerfRevisionState(revision_state.RevisionState):
12 17
13 """Contains the state and results for one revision in a perf bisect job.""" 18 """Contains the state and results for one revision in a perf bisect job."""
14 def __init__(self, *args, **kwargs): 19 def __init__(self, *args, **kwargs):
15 super(PerfRevisionState, self).__init__(*args, **kwargs) 20 super(PerfRevisionState, self).__init__(*args, **kwargs)
16 self.values = [] 21 self.values = []
17 self.mean_value = None 22 self.mean_value = None
18 self.std_err = None 23 self.std_err = None
24 self._test_config = None
19 25
20 def test_info(self): 26 def test_info(self):
21 """Returns a dictionary with information that describes this test. 27 """Returns a dictionary with information that describes this test.
22 28
23 It is meant to be used by the bisector to describe the test being run for 29 It is meant to be used by the bisector to describe the test being run for
24 each revision evaluated. 30 each revision evaluated.
25 """ 31 """
26 return { 32 return {
27 'command': self._test_config['command'], 33 'command': self._test_config['command'],
28 'metric': self._test_config['metric'], 34 'metric': self._test_config['metric'],
29 } 35 }
30 36
31 def _read_test_results(self): 37 def _read_test_results(self):
32 """Gets the test results from GS and checks if the rev is good or bad.""" 38 """Gets the test results from GS and checks if the rev is good or bad."""
33 results = self._get_test_results() 39 results = self._get_test_results()
34 # Results will contain the keys 'results' and 'output' where output is the 40 # Results will contain the keys 'results' and 'output' where output is the
35 # stdout of the command, and 'results' is itself a dict with the keys: 41 # stdout of the command, and 'results' is itself a dict with the keys:
36 # 'mean', 'values', 'std_err' 42 # 'mean', 'values', 'std_err'
37 results = results['results'] 43 results = results['results']
38 self.mean_value = results['mean'] 44 self.mean_value = results['mean']
39 self.values = results['values'] 45 self.values = results['values']
40 self.std_err = results['std_err'] 46 self.std_err = results['std_err']
41 # We cannot test the goodness of the initial rev range. 47 # We cannot test the goodness of the initial rev range.
42 if self.bisector.good_rev != self and self.bisector.bad_rev != self: 48 if self.bisector.good_rev != self and self.bisector.bad_rev != self:
43 if self._check_revision_good(): 49 if self._check_revision_good():
44 self.good = True 50 self.good = True
45 else: 51 else:
46 self.bad = True 52 self.bad = True
47 53
54 def _write_deps_patch_file(self, build_name):
55 api = self.bisector.api
56 file_name = os.path.join(tempfile.gettempdir(), build_name + '.diff')
57 api.m.file.write('Saving diff patch for ' + str(self.revision_string),
58 file_name, self.deps_patch + self.deps_sha_patch)
qyearsley 2015/03/10 23:20:49 Nit: Alignment.
RobertoCN 2015/03/13 20:55:59 Done.
59 return file_name
60
48 def _request_build(self): 61 def _request_build(self):
49 """Posts a request to buildbot to build this revision and archive it.""" 62 """Posts a request to buildbot to build this revision and archive it."""
50 # TODO: Rewrite using the trigger module. 63 # TODO: Rewrite using the trigger module.
51 # TODO: Send a diff patch when appropriate
52 api = self.bisector.api 64 api = self.bisector.api
53 bot_name = self.bisector.get_builder_bot_for_this_platform() 65 bot_name = self.bisector.get_builder_bot_for_this_platform()
54 if self.bisector.dummy_builds: 66 if self.bisector.dummy_builds:
55 self.build_job_name = self.commit_hash + '-build' 67 self.build_job_name = self.commit_hash + '-build'
56 else: # pragma: no cover 68 else: # pragma: no cover
57 self.build_job_name = uuid.uuid4().hex 69 self.build_job_name = uuid.uuid4().hex
70 if self.needs_patch:
71 self.patch_file = self._write_deps_patch_file(
72 self.build_job_name)
73 else:
74 self.patch_file = '/dev/null'
58 try_cmd = [ 75 try_cmd = [
59 'try', 76 'try',
60 '--bot=%s' % bot_name, 77 '--bot', bot_name,
61 '--revision=%s' % self.commit_hash, 78 '--revision', self.commit_hash,
62 '--name=%s' % self.build_job_name, 79 '--name', self.build_job_name,
63 '--svn_repo=%s' % api.SVN_REPO_URL, 80 '--svn_repo', api.SVN_REPO_URL,
64 '--diff', 81 '--email', api.BOT_EMAIL,
65 '/dev/null', 82 '--diff', self.patch_file,
66 ] 83 ]
67 api.m.git(*try_cmd, name='Requesting build for %s via git try.' 84 try:
68 % str(self.commit_hash)) 85 api.m.git(*try_cmd, name='Requesting build for %s via git try.'
86 % str(self.commit_hash))
87 finally:
88 if (self.patch_file != '/dev/null' and not 'TESTING_SLAVENAME' in
89 os.environ):
90 try:
91 api.m.step('cleaning up patch', ['rm', self.patch_file])
92 except api.m.step.StepFailure: # pragma: no cover
93 print 'Could not clean up ' + self.patch_file
69 94
70 def _get_bisect_config_for_tester(self): 95 def _get_bisect_config_for_tester(self):
71 """Copies the key-value pairs required by a tester bot to a new dict.""" 96 """Copies the key-value pairs required by a tester bot to a new dict."""
72 result = {} 97 result = {}
73 required_test_properties = { 98 required_test_properties = {
74 'truncate_percent', 99 'truncate_percent',
75 'metric', 100 'metric',
76 'max_time_minutes', 101 'max_time_minutes',
77 'command', 102 'command',
78 'repeat_count', 103 'repeat_count',
79 'test_type' 104 'test_type'
80 } 105 }
81 for k, v in self.bisector.bisect_config.iteritems(): 106 for k, v in self.bisector.bisect_config.iteritems():
82 if k in required_test_properties: 107 if k in required_test_properties:
83 result[k] = v 108 result[k] = v
84 self._test_config = result 109 self._test_config = result
85 return result 110 return result
86 111
87 def _do_test(self): 112 def _do_test(self):
88 """Posts a request to buildbot to download and perf-test this build.""" 113 """Posts a request to buildbot to download and perf-test this build."""
89 if self.bisector.dummy_builds: 114 if self.bisector.dummy_builds:
90 self.test_job_name = self.commit_hash + '-test' 115 self.test_job_name = self.commit_hash + '-test'
116 elif 'CACHE_TEST_RESULTS' in os.environ: # pragma: no cover
117 self.test_job_name = test_results_cache.make_id(
118 self.revision_string, self._get_bisect_config_for_tester())
91 else: # pragma: no cover 119 else: # pragma: no cover
92 self.test_job_name = uuid.uuid4().hex 120 self.test_job_name = uuid.uuid4().hex
93 api = self.bisector.api 121 api = self.bisector.api
94 perf_test_properties = { 122 perf_test_properties = {
95 'buildername': self.bisector.get_perf_tester_name(), 123 'buildername': self.bisector.get_perf_tester_name(),
96 'revision': self.revision_string, 124 'revision': self.revision_string,
97 'parent_build_archive_url': self.build_url, 125 'parent_build_archive_url': self.build_url,
98 'bisect_config': self._get_bisect_config_for_tester(), 126 'bisect_config': self._get_bisect_config_for_tester(),
99 'job_name': self.test_job_name, 127 'job_name': self.test_job_name,
100 } 128 }
129 if 'CACHE_TEST_RESULTS' in os.environ and test_results_cache.has_results(
130 self.test_job_name): # pragma: no cover
131 return
101 step_name = 'Triggering test job for ' + str(self.revision_string) 132 step_name = 'Triggering test job for ' + str(self.revision_string)
102 api.m.trigger(perf_test_properties, name=step_name) 133 api.m.trigger(perf_test_properties, name=step_name)
103 134
104 def _get_build_status(self): 135 def _get_build_status(self):
105 """Queries buildbot through the json API to check if the job is done.""" 136 """Queries buildbot through the json API to check if the job is done."""
106 api = self.bisector.api 137 api = self.bisector.api
107 try: 138 try:
108 stdout = api.m.raw_io.output() 139 stdout = api.m.raw_io.output()
109 name = 'Get test status for build ' + self.commit_hash 140 name = 'Get test status for build ' + self.commit_hash
110 step_result = api.m.python(name, api.resource('check_job_status.py'), 141 step_result = api.m.python(name, api.resource('check_job_status.py'),
(...skipping 17 matching lines...) Expand all
128 """ 159 """
129 api = self.bisector.api 160 api = self.bisector.api
130 url_file_url = api.GS_RESULTS_URL + self.test_job_name 161 url_file_url = api.GS_RESULTS_URL + self.test_job_name
131 try: 162 try:
132 stdout = api.m.raw_io.output() 163 stdout = api.m.raw_io.output()
133 name = 'Get test status url for build ' + self.commit_hash 164 name = 'Get test status url for build ' + self.commit_hash
134 step_result = api.m.gsutil.cat(url_file_url, stdout=stdout, name=name) 165 step_result = api.m.gsutil.cat(url_file_url, stdout=stdout, name=name)
135 except api.m.step.StepFailure: # pragma: no cover 166 except api.m.step.StepFailure: # pragma: no cover
136 return None 167 return None
137 else: 168 else:
138 return step_result.stdout 169 url = step_result.stdout
170 if 'CACHE_TEST_RESULTS' in os.environ: # pragma: no cover
171 test_results_cache.save_results(self.test_job_name, url)
172 return url
139 173
140 def get_next_url(self): 174 def get_next_url(self):
141 if not self.in_progress: 175 if not self.in_progress:
142 return None 176 return None
143 if not self.built: 177 if not self.built:
144 return self.build_url 178 return self.build_url
145 if not self.build_status_url: 179 if not self.build_status_url:
146 # The file that will eventually contain the buildbot job url 180 # The file that will eventually contain the buildbot job url
147 return self.bisector.api.GS_RESULTS_URL + self.test_job_name 181 return self.bisector.api.GS_RESULTS_URL + self.test_job_name
148 return self.build_status_url # pragma: no cover 182 return self.build_status_url # pragma: no cover
(...skipping 23 matching lines...) Expand all
172 True if this revision is closer to the initial good revision's value than 206 True if this revision is closer to the initial good revision's value than
173 to the initial bad revision's value. False otherwise. 207 to the initial bad revision's value. False otherwise.
174 """ 208 """
175 # TODO: Reevaluate this approach 209 # TODO: Reevaluate this approach
176 bisector = self.bisector 210 bisector = self.bisector
177 distance_to_good = abs(self.mean_value - bisector.good_rev.mean_value) 211 distance_to_good = abs(self.mean_value - bisector.good_rev.mean_value)
178 distance_to_bad = abs(self.mean_value - bisector.bad_rev.mean_value) 212 distance_to_bad = abs(self.mean_value - bisector.bad_rev.mean_value)
179 if distance_to_good < distance_to_bad: 213 if distance_to_good < distance_to_bad:
180 return True 214 return True
181 return False 215 return False
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698