Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium 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 """Compare the artifacts from two builds.""" | 6 """Compare the artifacts from two builds.""" |
| 7 | 7 |
| 8 import difflib | 8 import difflib |
| 9 import json | 9 import json |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import re | |
| 13 import subprocess | |
| 12 import struct | 14 import struct |
| 13 import sys | 15 import sys |
| 14 import time | 16 import time |
| 15 | 17 |
| 16 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | 18 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 17 | 19 |
| 18 | 20 |
| 19 # List of files that are known to be non deterministic. This is a "temporary" | 21 # List of files that are known to be non deterministic. This is a "temporary" |
| 20 # workaround to find regression on the deterministic builders. | 22 # workaround to find regression on the deterministic builders. |
| 21 # | 23 # |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 488 # else, falls through binary comparison, it must be binary equal too. | 490 # else, falls through binary comparison, it must be binary equal too. |
| 489 | 491 |
| 490 file_len = os.stat(first_filepath).st_size | 492 file_len = os.stat(first_filepath).st_size |
| 491 if file_len != os.stat(second_filepath).st_size: | 493 if file_len != os.stat(second_filepath).st_size: |
| 492 return 'different size: %d != %d' % ( | 494 return 'different size: %d != %d' % ( |
| 493 file_len, os.stat(second_filepath).st_size) | 495 file_len, os.stat(second_filepath).st_size) |
| 494 | 496 |
| 495 return diff_binary(first_filepath, second_filepath, file_len) | 497 return diff_binary(first_filepath, second_filepath, file_len) |
| 496 | 498 |
| 497 | 499 |
| 500 def get_deps(build_dir, target): | |
| 501 """Returns list of object files needed to build target.""" | |
| 502 NODE_PATTERN = re.compile(r'label="([a-zA-Z0-9_\\/.-]+)"') | |
| 503 CHECK_EXTS = ('.o', '.obj') | |
| 504 try: | |
| 505 out = subprocess.check_output(['ninja', '-C', build_dir, | |
|
M-A Ruel
2016/08/24 18:47:27
There's a problem as the directory was renamed, so
Yoshisato Yanagisawa
2016/08/25 08:47:29
I have never seen absolute object file path names
M-A Ruel
2016/08/25 15:46:26
zforman@ worked on making this work on linux but t
Yoshisato Yanagisawa
2016/08/29 05:44:49
I checked the code seems to work on Win.
| |
| 506 '-t', 'graph', target]) | |
| 507 except subprocess.CalledProcessError as e: | |
| 508 print >> sys.stderr, 'error to get graph for %s: %s' % (target, e) | |
| 509 return [] | |
| 510 files = [] | |
| 511 for line in out.splitlines(): | |
| 512 matched = NODE_PATTERN.search(line) | |
| 513 if matched: | |
| 514 path = matched.group(1) | |
| 515 if not os.path.splitext(path)[1] in CHECK_EXTS: | |
| 516 continue | |
| 517 files.append(path) | |
| 518 return files | |
| 519 | |
| 520 | |
| 521 def compare_deps(first_dir, second_dir, targets): | |
| 522 """Print difference of dependent files.""" | |
| 523 for target in targets: | |
| 524 print 'Checking %s difference:' % target | |
| 525 first_deps = get_deps(first_dir, target) | |
| 526 second_deps = get_deps(second_dir, target) | |
| 527 deps = set(first_deps).union(set(second_deps)) | |
|
M-A Ruel
2016/08/24 18:47:27
the difference should be empty ?
Yoshisato Yanagisawa
2016/08/25 08:47:29
I am not confident. However, I will simplify the
M-A Ruel
2016/08/25 15:46:26
I guess my question was more to print out the diff
Yoshisato Yanagisawa
2016/08/29 05:44:49
I think current code still help us to find this ki
| |
| 528 for d in deps: | |
| 529 first_file = os.path.join(first_dir, d) | |
| 530 second_file = os.path.join(second_dir, d) | |
| 531 if not os.path.exists(first_file): | |
| 532 print '%s: not found' % first_file | |
| 533 continue | |
| 534 if not os.path.exists(second_file): | |
| 535 print '%s: not found' % second_file | |
| 536 continue | |
| 537 compare_files(first_file, second_file) | |
| 538 | |
| 539 | |
| 498 def compare_build_artifacts(first_dir, second_dir, target_platform, | 540 def compare_build_artifacts(first_dir, second_dir, target_platform, |
| 499 recursive=False): | 541 recursive=False): |
| 500 """Compares the artifacts from two distinct builds.""" | 542 """Compares the artifacts from two distinct builds.""" |
| 501 if not os.path.isdir(first_dir): | 543 if not os.path.isdir(first_dir): |
| 502 print >> sys.stderr, '%s isn\'t a valid directory.' % first_dir | 544 print >> sys.stderr, '%s isn\'t a valid directory.' % first_dir |
| 503 return 1 | 545 return 1 |
| 504 if not os.path.isdir(second_dir): | 546 if not os.path.isdir(second_dir): |
| 505 print >> sys.stderr, '%s isn\'t a valid directory.' % second_dir | 547 print >> sys.stderr, '%s isn\'t a valid directory.' % second_dir |
| 506 return 1 | 548 return 1 |
| 507 | 549 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 print('Unexpected diffs: %d' % len(unexpected_diffs)) | 596 print('Unexpected diffs: %d' % len(unexpected_diffs)) |
| 555 if unexpected_diffs: | 597 if unexpected_diffs: |
| 556 print('Unexpected files with diffs:\n') | 598 print('Unexpected files with diffs:\n') |
| 557 for u in unexpected_diffs: | 599 for u in unexpected_diffs: |
| 558 print(' %s' % u) | 600 print(' %s' % u) |
| 559 if unexpected_equals: | 601 if unexpected_equals: |
| 560 print('Unexpected files with no diffs:\n') | 602 print('Unexpected files with no diffs:\n') |
| 561 for u in unexpected_equals: | 603 for u in unexpected_equals: |
| 562 print(' %s' % u) | 604 print(' %s' % u) |
| 563 | 605 |
| 606 if unexpected_diffs: | |
| 607 diffs_to_investigate = set(unexpected_diffs).difference( | |
| 608 set(missing_files)) | |
| 609 compare_deps(first_dir, second_dir, diffs_to_investigate) | |
| 610 | |
| 564 return int(bool(unexpected_diffs)) | 611 return int(bool(unexpected_diffs)) |
| 565 | 612 |
| 566 | 613 |
| 567 def main(): | 614 def main(): |
| 568 parser = optparse.OptionParser(usage='%prog [options]') | 615 parser = optparse.OptionParser(usage='%prog [options]') |
| 569 parser.add_option( | 616 parser.add_option( |
| 570 '-f', '--first-build-dir', help='The first build directory.') | 617 '-f', '--first-build-dir', help='The first build directory.') |
| 571 parser.add_option( | 618 parser.add_option( |
| 572 '-s', '--second-build-dir', help='The second build directory.') | 619 '-s', '--second-build-dir', help='The second build directory.') |
| 573 parser.add_option('-r', '--recursive', action='store_true', default=False, | 620 parser.add_option('-r', '--recursive', action='store_true', default=False, |
| 574 help='Indicates if the comparison should be recursive.') | 621 help='Indicates if the comparison should be recursive.') |
| 575 target = { | 622 target = { |
| 576 'darwin': 'mac', 'linux2': 'linux', 'win32': 'win' | 623 'darwin': 'mac', 'linux2': 'linux', 'win32': 'win' |
| 577 }.get(sys.platform, sys.platform) | 624 }.get(sys.platform, sys.platform) |
| 578 parser.add_option('-t', '--target-platform', help='The target platform.' | 625 parser.add_option('-t', '--target-platform', help='The target platform.', |
| 579 default=target, choices=('android', 'mac', 'linux', 'win')) | 626 default=target, choices=('android', 'mac', 'linux', 'win')) |
| 580 options, _ = parser.parse_args() | 627 options, _ = parser.parse_args() |
| 581 | 628 |
| 582 if not options.first_build_dir: | 629 if not options.first_build_dir: |
| 583 parser.error('--first-build-dir is required') | 630 parser.error('--first-build-dir is required') |
| 584 if not options.second_build_dir: | 631 if not options.second_build_dir: |
| 585 parser.error('--second-build-dir is required') | 632 parser.error('--second-build-dir is required') |
| 586 if not options.target_platform: | 633 if not options.target_platform: |
| 587 parser.error('--target-platform is required') | 634 parser.error('--target-platform is required') |
| 588 | 635 |
| 589 return compare_build_artifacts(os.path.abspath(options.first_build_dir), | 636 return compare_build_artifacts(os.path.abspath(options.first_build_dir), |
| 590 os.path.abspath(options.second_build_dir), | 637 os.path.abspath(options.second_build_dir), |
| 591 options.target_platform, | 638 options.target_platform, |
| 592 options.recursive) | 639 options.recursive) |
| 593 | 640 |
| 594 | 641 |
| 595 if __name__ == '__main__': | 642 if __name__ == '__main__': |
| 596 sys.exit(main()) | 643 sys.exit(main()) |
| OLD | NEW |