| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright 2017 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Merge the PGC files generated during the profiling step to the PGD database. | |
| 7 | |
| 8 This is required to workaround a flakyness in pgomgr.exe where it can run out | |
| 9 of address space while trying to merge all the PGC files at the same time. | |
| 10 """ | |
| 11 | |
| 12 import glob | |
| 13 import json | |
| 14 import optparse | |
| 15 import os | |
| 16 import subprocess | |
| 17 import sys | |
| 18 | |
| 19 | |
| 20 def find_pgomgr(chrome_checkout_dir, target_cpu): | |
| 21 """Find pgomgr.exe.""" | |
| 22 if target_cpu not in ('x86', 'x64'): | |
| 23 raise Exception('target_cpu should be x86 or x64.') | |
| 24 | |
| 25 win_toolchain_json_file = os.path.join(chrome_checkout_dir, 'build', | |
| 26 'win_toolchain.json') | |
| 27 if not os.path.exists(win_toolchain_json_file): | |
| 28 raise Exception('The toolchain JSON file is missing.') | |
| 29 with open(win_toolchain_json_file) as temp_f: | |
| 30 toolchain_data = json.load(temp_f) | |
| 31 if not os.path.isdir(toolchain_data['path']): | |
| 32 raise Exception('The toolchain JSON file is invalid.') | |
| 33 | |
| 34 pgomgr_dir = os.path.join(toolchain_data['path'], 'VC', 'bin') | |
| 35 if target_cpu == 'x64': | |
| 36 pgomgr_dir = os.path.join(pgomgr_dir, 'amd64') | |
| 37 | |
| 38 pgomgr_path = os.path.join(pgomgr_dir, 'pgomgr.exe') | |
| 39 if not os.path.exists(pgomgr_path): | |
| 40 raise Exception('pgomgr.exe is missing from %s.' % pgomgr_dir) | |
| 41 | |
| 42 return pgomgr_path | |
| 43 | |
| 44 | |
| 45 def main(): | |
| 46 parser = optparse.OptionParser(usage='%prog [options]') | |
| 47 parser.add_option('--checkout-dir', help='The Chrome checkout directory.') | |
| 48 parser.add_option('--target-cpu', help='The target\'s bitness.') | |
| 49 parser.add_option('--build-dir', help='Chrome build directory.') | |
| 50 parser.add_option('--binary-name', help='The binary for which the PGC files ' | |
| 51 'should be merged, without extension.') | |
| 52 options, _ = parser.parse_args() | |
| 53 | |
| 54 if not options.checkout_dir: | |
| 55 parser.error('--checkout-dir is required') | |
| 56 if not options.target_cpu: | |
| 57 parser.error('--target-cpu is required') | |
| 58 if not options.build_dir: | |
| 59 parser.error('--build-dir is required') | |
| 60 if not options.binary_name: | |
| 61 parser.error('--binary-name is required') | |
| 62 | |
| 63 # Starts by finding pgomgr.exe. | |
| 64 pgomgr_path = find_pgomgr(options.checkout_dir, options.target_cpu) | |
| 65 | |
| 66 pgc_files = glob.glob(os.path.join(options.build_dir, | |
| 67 '%s*.pgc' % options.binary_name)) | |
| 68 | |
| 69 # Number of PGC files that should be merged in each iterations, merging all | |
| 70 # the files one by one is really slow but merging more to 10 at a time doesn't | |
| 71 # really seem to impact the total time. | |
| 72 # | |
| 73 # Number of pgc merged per iteration | Time (in min) | |
| 74 # 1 | 27.2 | |
| 75 # 10 | 12.8 | |
| 76 # 20 | 12.0 | |
| 77 # 30 | 11.5 | |
| 78 # 40 | 11.4 | |
| 79 # 50 | 11.5 | |
| 80 # 60 | 11.6 | |
| 81 # 70 | 11.6 | |
| 82 # 80 | 11.7 | |
| 83 # | |
| 84 # TODO(sebmarchand): Measure the memory usage of pgomgr.exe to see how it get | |
| 85 # affected by the number of pgc files. | |
| 86 pgc_per_iter = 20 | |
| 87 | |
| 88 def _split_in_chunks(items, chunk_size): | |
| 89 """Split |items| in chunks of size |chunk_size|. | |
| 90 | |
| 91 Source: http://stackoverflow.com/a/312464 | |
| 92 """ | |
| 93 for i in xrange(0, len(items), chunk_size): | |
| 94 yield items[i:i + chunk_size] | |
| 95 | |
| 96 for chunk in _split_in_chunks(pgc_files, pgc_per_iter): | |
| 97 merge_command = [ | |
| 98 pgomgr_path, | |
| 99 '/merge' | |
| 100 ] | |
| 101 for pgc_file in chunk: | |
| 102 merge_command.append([ | |
| 103 os.path.join(options.build_dir, pgc_file) | |
| 104 ]) | |
| 105 | |
| 106 merge_command.append([ | |
| 107 os.path.join(options.build_dir, '%s.pgd' % options.binary_name) | |
| 108 ]) | |
| 109 proc = subprocess.Popen(merge_command, stdout=subprocess.PIPE) | |
| 110 stdout, _ = proc.communicate() | |
| 111 if proc.returncode != 0: | |
| 112 raise Exception('Error while trying to merge the PGC files:\n%s' % stdout) | |
| 113 | |
| 114 | |
| 115 if __name__ == '__main__': | |
| 116 sys.exit(main()) | |
| OLD | NEW |