| OLD | NEW |
| 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 """An interface for holding state and result of revisions in a bisect job. | 5 """An interface for holding state and result of revisions in a bisect job. |
| 6 | 6 |
| 7 When implementing support for tests other than perf, one should extend this | 7 When implementing support for tests other than perf, one should extend this |
| 8 class so that the bisect module and recipe can use it. | 8 class so that the bisect module and recipe can use it. |
| 9 | 9 |
| 10 See perf_revision_state for an example. | 10 See perf_revision_state for an example. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 self.next_revision = None | 65 self.next_revision = None |
| 66 self.previous_revision = None | 66 self.previous_revision = None |
| 67 self.job_name = None | 67 self.job_name = None |
| 68 self.patch_file = None | 68 self.patch_file = None |
| 69 self.deps_revision = None | 69 self.deps_revision = None |
| 70 self.depot_name = depot_name or self.bisector.base_depot | 70 self.depot_name = depot_name or self.bisector.base_depot |
| 71 self.depot = depot_config.DEPOT_DEPS_NAME[self.depot_name] | 71 self.depot = depot_config.DEPOT_DEPS_NAME[self.depot_name] |
| 72 self.commit_hash = str(commit_hash) | 72 self.commit_hash = str(commit_hash) |
| 73 self._rev_str = None | 73 self._rev_str = None |
| 74 self.base_revision = base_revision | 74 self.base_revision = base_revision |
| 75 self.top_revision = self |
| 76 # The difference between revsion overrides and revsion ladder is that the |
| 77 # former is indexed by paths, e.g. 'src/third_party/skia' and the latter is |
| 78 # indexed by depot name, e.g. 'skia'. |
| 75 self.revision_overrides = {} | 79 self.revision_overrides = {} |
| 80 self.revision_ladder = {self.depot_name: self.commit_hash} |
| 76 self.build_id = None | 81 self.build_id = None |
| 77 if self.base_revision: | 82 if self.base_revision: |
| 78 assert self.base_revision.deps_file_contents | 83 assert self.base_revision.deps_file_contents |
| 79 self.needs_patch = True | 84 self.needs_patch = True |
| 80 self.revision_overrides[self.depot['src']] = self.commit_hash | 85 self.revision_overrides[self.depot['src']] = self.commit_hash |
| 86 # To allow multiple nested levels, we go to the topmost revision. |
| 87 while self.top_revision.base_revision: |
| 88 self.top_revision = self.top_revision.base_revision |
| 89 # We want to carry over any overrides from the base revision(s) without |
| 90 # overwriting any overrides specified at the self level. |
| 91 self.revision_ladder[self.top_revision.depot_name] = ( |
| 92 self.top_revision.commit_hash) |
| 93 self.revision_overrides = dict( |
| 94 self.top_revision.revision_overrides.items() + |
| 95 self.revision_overrides.items()) |
| 81 self.deps_patch, self.deps_file_contents = self.bisector.make_deps_patch( | 96 self.deps_patch, self.deps_file_contents = self.bisector.make_deps_patch( |
| 82 self.base_revision, self.base_revision.deps_file_contents, | 97 self.base_revision, self.base_revision.deps_file_contents, |
| 83 self.depot, self.commit_hash) | 98 self.depot, self.commit_hash) |
| 84 self.deps_sha = hashlib.sha1(self.deps_patch).hexdigest() | 99 self.deps_sha = hashlib.sha1(self.deps_patch).hexdigest() |
| 85 self.deps_sha_patch = self.bisector.make_deps_sha_file(self.deps_sha) | 100 self.deps_sha_patch = self.bisector.make_deps_sha_file(self.deps_sha) |
| 86 self.deps = dict(base_revision.deps) | 101 self.deps = dict(base_revision.deps) |
| 87 self.deps[self.depot_name] = self.commit_hash | 102 self.deps[self.depot_name] = self.commit_hash |
| 88 else: | 103 else: |
| 89 self.needs_patch = False | 104 self.needs_patch = False |
| 90 self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix() | 105 self.build_url = self.bisector.get_platform_gs_prefix() + self._gs_suffix() |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 result = api.gsutil_file_exists(self.test_results_url) | 312 result = api.gsutil_file_exists(self.test_results_url) |
| 298 if self.bisector.dummy_builds: | 313 if self.bisector.dummy_builds: |
| 299 return self.in_progress | 314 return self.in_progress |
| 300 return result # pragma: no cover | 315 return result # pragma: no cover |
| 301 | 316 |
| 302 def _gs_suffix(self): | 317 def _gs_suffix(self): |
| 303 """Provides the expected right half of the build filename. | 318 """Provides the expected right half of the build filename. |
| 304 | 319 |
| 305 This takes into account whether the build has a deps patch. | 320 This takes into account whether the build has a deps patch. |
| 306 """ | 321 """ |
| 307 top_revision = self | 322 name_parts = [self.top_revision.commit_hash] |
| 308 while top_revision.base_revision: | |
| 309 top_revision = top_revision.base_revision | |
| 310 name_parts = [top_revision.commit_hash] | |
| 311 if self.needs_patch: | 323 if self.needs_patch: |
| 312 name_parts.append(self.deps_sha) | 324 name_parts.append(self.deps_sha) |
| 313 return '%s.zip' % '_'.join(name_parts) | 325 return '%s.zip' % '_'.join(name_parts) |
| 314 | 326 |
| 315 def _read_test_results(self, check_revision_goodness=True): | 327 def _read_test_results(self, check_revision_goodness=True): |
| 316 """Gets the test results from GS and checks if the rev is good or bad.""" | 328 """Gets the test results from GS and checks if the rev is good or bad.""" |
| 317 test_results = self._get_test_results() | 329 test_results = self._get_test_results() |
| 318 # Results will contain the keys 'results' and 'output' where output is the | 330 # Results will contain the keys 'results' and 'output' where output is the |
| 319 # stdout of the command, and 'results' is itself a dict with the key | 331 # stdout of the command, and 'results' is itself a dict with the key |
| 320 # 'values' unless the test failed, in which case 'results' will contain | 332 # 'values' unless the test failed, in which case 'results' will contain |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 check_revision_goodness): | 374 check_revision_goodness): |
| 363 if self._check_revision_good(): | 375 if self._check_revision_good(): |
| 364 self.good = True | 376 self.good = True |
| 365 else: | 377 else: |
| 366 self.bad = True | 378 self.bad = True |
| 367 | 379 |
| 368 def _request_build(self): | 380 def _request_build(self): |
| 369 """Posts a request to buildbot to build this revision and archive it.""" | 381 """Posts a request to buildbot to build this revision and archive it.""" |
| 370 api = self.bisector.api | 382 api = self.bisector.api |
| 371 bot_name = self.bisector.get_builder_bot_for_this_platform() | 383 bot_name = self.bisector.get_builder_bot_for_this_platform() |
| 372 | |
| 373 # To allow multiple nested levels, we go to the topmost revision. | |
| 374 top_revision = self | |
| 375 while top_revision.base_revision: | |
| 376 top_revision = top_revision.base_revision | |
| 377 # We want to carry over any overrides from the base revision(s) without | |
| 378 # overwriting any overrides specified at the self level. | |
| 379 self.revision_overrides = dict(top_revision.revision_overrides.items() + | |
| 380 self.revision_overrides.items()) | |
| 381 | |
| 382 operation_id = 'dummy' if self.bisector.dummy_tests else uuid.uuid4().hex | 384 operation_id = 'dummy' if self.bisector.dummy_tests else uuid.uuid4().hex |
| 383 build_details = { | 385 build_details = { |
| 384 'bucket': 'master.' + api.m.properties['mastername'], | 386 'bucket': 'master.' + api.m.properties['mastername'], |
| 385 'parameters': { | 387 'parameters': { |
| 386 'builder_name': bot_name, | 388 'builder_name': bot_name, |
| 387 'properties': { | 389 'properties': { |
| 388 'parent_got_revision': top_revision.commit_hash, | 390 'parent_got_revision': self.top_revision.commit_hash, |
| 389 'clobber': True, | 391 'clobber': True, |
| 390 'build_archive_url': self.build_url, | 392 'build_archive_url': self.build_url, |
| 391 }, | 393 }, |
| 392 }, | 394 }, |
| 393 'client_operation_id': operation_id | 395 'client_operation_id': operation_id |
| 394 } | 396 } |
| 395 if self.revision_overrides: | 397 if self.revision_overrides: |
| 396 build_details['parameters']['properties']['deps_revision_overrides'] = \ | 398 build_details['parameters']['properties']['deps_revision_overrides'] = \ |
| 397 self.revision_overrides | 399 self.revision_overrides |
| 398 | 400 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 429 | 431 |
| 430 If local testing is enabled (i.e. director/tester merged) then | 432 If local testing is enabled (i.e. director/tester merged) then |
| 431 the test will be run on the same machine. Otherwise, this posts | 433 the test will be run on the same machine. Otherwise, this posts |
| 432 a request to buildbot to download and perf-test this build. | 434 a request to buildbot to download and perf-test this build. |
| 433 """ | 435 """ |
| 434 if self.bisector.bisect_config.get('dummy_job_names'): | 436 if self.bisector.bisect_config.get('dummy_job_names'): |
| 435 self.job_name = self.commit_hash + '-test' | 437 self.job_name = self.commit_hash + '-test' |
| 436 else: # pragma: no cover | 438 else: # pragma: no cover |
| 437 self.job_name = uuid.uuid4().hex | 439 self.job_name = uuid.uuid4().hex |
| 438 api = self.bisector.api | 440 api = self.bisector.api |
| 439 # Stores revision map for different repos eg, android-chrome, src, v8 etc. | |
| 440 revision_ladder = {} | |
| 441 top_revision = self | |
| 442 revision_ladder[top_revision.depot_name] = top_revision.commit_hash | |
| 443 while top_revision.base_revision: # pragma: no cover | |
| 444 revision_ladder[top_revision.depot_name] = top_revision.commit_hash | |
| 445 top_revision = top_revision.base_revision | |
| 446 perf_test_properties = { | 441 perf_test_properties = { |
| 447 'builder_name': self.bisector.get_perf_tester_name(), | 442 'builder_name': self.bisector.get_perf_tester_name(), |
| 448 'properties': { | 443 'properties': { |
| 449 'revision': top_revision.commit_hash, | 444 'revision': self.top_revision.commit_hash, |
| 450 'parent_got_revision': top_revision.commit_hash, | 445 'parent_got_revision': self.top_revision.commit_hash, |
| 451 'parent_build_archive_url': self.build_url, | 446 'parent_build_archive_url': self.build_url, |
| 452 'bisect_config': self._get_bisect_config_for_tester(), | 447 'bisect_config': self._get_bisect_config_for_tester(), |
| 453 'job_name': self.job_name, | 448 'job_name': self.job_name, |
| 454 'revision_ladder': revision_ladder, | 449 'revision_ladder': self.revision_ladder, |
| 450 'deps_revision_overrides': self.revision_overrides, |
| 455 }, | 451 }, |
| 456 } | 452 } |
| 457 self.test_results_url = (self.bisector.api.GS_RESULTS_URL + | 453 self.test_results_url = (self.bisector.api.GS_RESULTS_URL + |
| 458 self.job_name + '.results') | 454 self.job_name + '.results') |
| 459 if (api.m.bisect_tester.local_test_enabled() or | 455 if (api.m.bisect_tester.local_test_enabled() or |
| 460 self.bisector.internal_bisect): # pragma: no cover | 456 self.bisector.internal_bisect): # pragma: no cover |
| 461 skip_download = self.bisector.last_tested_revision == self | 457 skip_download = self.bisector.last_tested_revision == self |
| 462 self.bisector.last_tested_revision = self | 458 self.bisector.last_tested_revision = self |
| 463 overrides = perf_test_properties['properties'] | 459 overrides = perf_test_properties['properties'] |
| 464 api.run_local_test_run(overrides, skip_download=skip_download) | 460 api.run_local_test_run(overrides, skip_download=skip_download) |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 else: | 569 else: |
| 574 next_revision_to_test.retest() | 570 next_revision_to_test.retest() |
| 575 | 571 |
| 576 def __repr__(self): | 572 def __repr__(self): |
| 577 if self.overall_return_code is not None: | 573 if self.overall_return_code is not None: |
| 578 return ('RevisionState(rev=%s, values=%r, overall_return_code=%r, ' | 574 return ('RevisionState(rev=%s, values=%r, overall_return_code=%r, ' |
| 579 'std_dev=%r)') % (self.revision_string(), self.values, | 575 'std_dev=%r)') % (self.revision_string(), self.values, |
| 580 self.overall_return_code, self.std_dev) | 576 self.overall_return_code, self.std_dev) |
| 581 return ('RevisionState(rev=%s, values=%r, mean_value=%r, std_dev=%r)' % ( | 577 return ('RevisionState(rev=%s, values=%r, mean_value=%r, std_dev=%r)' % ( |
| 582 self.revision_string(), self.values, self.mean_value, self.std_dev)) | 578 self.revision_string(), self.values, self.mean_value, self.std_dev)) |
| OLD | NEW |