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

Side by Side Diff: scripts/slave/compile.py

Issue 2178193003: Move goma_teardown, goma_setup and determine_goma_jobs to goma_utils.py (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Created 4 years, 4 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
« no previous file with comments | « no previous file | scripts/slave/goma_utils.py » ('j') | scripts/slave/goma_utils.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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 """A tool to build chrome, executed by buildbot. 6 """A tool to build chrome, executed by buildbot.
7 7
8 When this is run, the current directory (cwd) should be the outer build 8 When this is run, the current directory (cwd) should be the outer build
9 directory (e.g., chrome-release/build/). 9 directory (e.g., chrome-release/build/).
10 10
11 For a list of command-line options, call this script with '--help'. 11 For a list of command-line options, call this script with '--help'.
12 """ 12 """
13 13
14 import multiprocessing
15 import optparse 14 import optparse
16 import os 15 import os
17 import re 16 import re
18 import subprocess
19 import sys 17 import sys
20 18
21 from common import chromium_utils 19 from common import chromium_utils
22 from slave import build_directory 20 from slave import build_directory
23 from slave import goma_utils 21 from slave import goma_utils
24 22
25 # Define a bunch of directory paths (same as bot_update.py) 23 # Define a bunch of directory paths (same as bot_update.py)
26 CURRENT_DIR = os.path.abspath(os.getcwd()) 24 CURRENT_DIR = os.path.abspath(os.getcwd())
27 BUILDER_DIR = os.path.dirname(CURRENT_DIR) 25 BUILDER_DIR = os.path.dirname(CURRENT_DIR)
28 SLAVE_DIR = os.path.dirname(BUILDER_DIR) 26 SLAVE_DIR = os.path.dirname(BUILDER_DIR)
29 # GOMA_CACHE_DIR used for caching long-term data. 27 # GOMA_CACHE_DIR used for caching long-term data.
30 DEFAULT_GOMA_CACHE_DIR = os.path.join(SLAVE_DIR, 'goma_cache') 28 DEFAULT_GOMA_CACHE_DIR = os.path.join(SLAVE_DIR, 'goma_cache')
ukai 2016/07/27 01:13:29 can't move it to goma_utils?
tikuta 2016/07/27 02:33:30 Done.
31 29
32 # Path of the scripts/slave/ checkout on the slave, found by looking at the 30 # Path of the scripts/slave/ checkout on the slave, found by looking at the
33 # current compile.py script's path's dirname(). 31 # current compile.py script's path's dirname().
34 SLAVE_SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__)) 32 SLAVE_SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
35 # Path of the build/ checkout on the slave, found relative to the 33 # Path of the build/ checkout on the slave, found relative to the
36 # scripts/slave/ directory. 34 # scripts/slave/ directory.
37 BUILD_DIR = os.path.dirname(os.path.dirname(SLAVE_SCRIPTS_DIR)) 35 BUILD_DIR = os.path.dirname(os.path.dirname(SLAVE_SCRIPTS_DIR))
38 36
39 37
40 class EchoDict(dict): 38 class EchoDict(dict):
(...skipping 24 matching lines...) Expand all
65 fh = sys.stdout 63 fh = sys.stdout
66 fh.write('Environment variables modified in compile.py:\n') 64 fh.write('Environment variables modified in compile.py:\n')
67 for k in sorted(list(self.overrides)): 65 for k in sorted(list(self.overrides)):
68 if k in self: 66 if k in self:
69 fh.write(' %s=%s\n' % (k, self[k])) 67 fh.write(' %s=%s\n' % (k, self[k]))
70 else: 68 else:
71 fh.write(' %s (removed)\n' % k) 69 fh.write(' %s (removed)\n' % k)
72 fh.write('\n') 70 fh.write('\n')
73 71
74 72
75 # TODO(tikuta): move to goma_utils.py
76 def goma_setup(options, env):
77 """Sets up goma if necessary.
78
79 If using the Goma compiler, first call goma_ctl to ensure the proxy is
80 available, and returns (True, instance of cloudtail subprocess).
81 If it failed to start up compiler_proxy, modify options.compiler and
82 options.goma_dir and returns (False, None)
83
84 """
85 if options.compiler not in ('goma', 'goma-clang'):
86 # Unset goma_dir to make sure we'll not use goma.
87 options.goma_dir = None
88 return False, None
89
90 hostname = goma_utils.GetShortHostname()
91 # HACK(shinyak, yyanagisawa, goma): Windows NO_NACL_GOMA (crbug.com/390764)
92 # Building NaCl untrusted code using goma brings large performance
93 # improvement but it sometimes cause build failure by race condition.
94 # Let me enable goma build on goma canary buildslaves to confirm the issue
95 # has been fixed by a workaround.
96 # vm*-m4 are trybots. build*-m1 and vm*-m1 are all goma canary bots.
97 if hostname in ['build28-m1', 'build58-m1', 'vm191-m1', 'vm480-m1',
98 'vm820-m1', 'vm821-m1', 'vm848-m1']:
99 env['NO_NACL_GOMA'] = 'false'
100
101 if options.goma_fail_fast:
102 # startup fails when initial ping failed.
103 env['GOMA_FAIL_FAST'] = 'true'
104 else:
105 # If a network error continues 30 minutes, compiler_proxy make the compile
106 # failed. When people use goma, they expect using goma is faster than
107 # compile locally. If goma cannot guarantee that, let it make compile
108 # as error.
109 env['GOMA_ALLOWED_NETWORK_ERROR_DURATION'] = '1800'
110
111 # HACK(yyanagisawa): reduce GOMA_BURST_MAX_PROCS crbug.com/592306
112 # Recently, I sometimes see buildbot slave time out, one possibility I come
113 # up with is burst mode use up resource.
114 # Let me temporary set small values to GOMA_BURST_MAX_PROCS to confirm
115 # the possibility is true or false.
116 max_subprocs = '3'
117 max_heavy_subprocs = '1'
118 number_of_processors = 0
119 try:
120 number_of_processors = multiprocessing.cpu_count()
121 except NotImplementedError:
122 print 'cpu_count() is not implemented, using default value.'
123 number_of_processors = 1
124 if number_of_processors > 3:
125 max_subprocs = str(number_of_processors - 1)
126 max_heavy_subprocs = str(number_of_processors / 2)
127 env['GOMA_BURST_MAX_SUBPROCS'] = max_subprocs
128 env['GOMA_BURST_MAX_SUBPROCS_LOW'] = max_subprocs
129 env['GOMA_BURST_MAX_SUBPROCS_HEAVY'] = max_heavy_subprocs
130
131 # Caches CRLs in GOMA_CACHE_DIR.
132 # Since downloading CRLs is usually slow, caching them may improves
133 # compiler_proxy start time.
134 if not os.path.exists(options.goma_cache_dir):
135 os.mkdir(options.goma_cache_dir, 0700)
136 env['GOMA_CACHE_DIR'] = options.goma_cache_dir
137
138 # Enable DepsCache. DepsCache caches the list of files to send goma server.
139 # This will greatly improve build speed when cache is warmed.
140 # The cache file is stored in the target output directory.
141 env['GOMA_DEPS_CACHE_DIR'] = (
142 options.goma_deps_cache_dir or options.target_output_dir)
143
144 if not env.get('GOMA_HERMETIC'):
145 env['GOMA_HERMETIC'] = options.goma_hermetic
146 if options.goma_enable_remote_link:
147 env['GOMA_ENABLE_REMOTE_LINK'] = options.goma_enable_remote_link
148 if options.goma_store_local_run_output:
149 env['GOMA_STORE_LOCAL_RUN_OUTPUT'] = options.goma_store_local_run_output
150 if options.goma_enable_compiler_info_cache:
151 # Will be stored in GOMA_CACHE_DIR.
152 env['GOMA_COMPILER_INFO_CACHE_FILE'] = 'goma-compiler-info.cache'
153
154 if options.build_data_dir:
155 env['GOMA_DUMP_STATS_FILE'] = os.path.join(options.build_data_dir,
156 'goma_stats_proto')
157
158 # goma is requested.
159 goma_key = os.path.join(options.goma_dir, 'goma.key')
160 if os.path.exists(goma_key):
161 env['GOMA_API_KEY_FILE'] = goma_key
162 if options.goma_service_account_json_file:
163 env['GOMA_SERVICE_ACCOUNT_JSON_FILE'] = \
164 options.goma_service_account_json_file
165 if chromium_utils.IsWindows():
166 env['GOMA_RPC_EXTRA_PARAMS'] = '?win'
167 goma_start_command = ['restart']
168 goma_ctl_cmd = [sys.executable,
169 os.path.join(options.goma_dir, 'goma_ctl.py')]
170 result = chromium_utils.RunCommand(goma_ctl_cmd + goma_start_command, env=env)
171 if not result:
172 # goma started sucessfully.
173 # Making cloudtail to upload the latest log.
174 # TODO(yyanagisawa): install cloudtail from CIPD.
175 cloudtail_path = '/opt/infra-tools/cloudtail'
176 if chromium_utils.IsWindows():
177 cloudtail_path = 'C:\\infra-tools\\cloudtail'
178 try:
179 cloudtail_proc = subprocess.Popen(
180 [cloudtail_path, 'tail', '--log-id', 'goma_compiler_proxy', '--path',
181 goma_utils.GetLatestGomaCompilerProxyInfo()])
182 except Exception as e:
183 print 'failed to invoke cloudtail: %s' % e
184 return True, None
185 return True, cloudtail_proc
186
187 if options.goma_jsonstatus:
188 chromium_utils.RunCommand(
189 goma_ctl_cmd + ['jsonstatus', options.goma_jsonstatus], env=env)
190 goma_utils.SendGomaTsMon(options.goma_jsonstatus, -1)
191
192 # Try to stop compiler_proxy so that it flushes logs and stores
193 # GomaStats.
194 if options.build_data_dir:
195 env['GOMACTL_CRASH_REPORT_ID_FILE'] = os.path.join(options.build_data_dir,
196 'crash_report_id_file')
197 chromium_utils.RunCommand(goma_ctl_cmd + ['stop'], env=env)
198
199 override_gsutil = None
200 if options.gsutil_py_path:
201 override_gsutil = [sys.executable, options.gsutil_py_path]
202
203 # Upload compiler_proxy.INFO to investigate the reason of compiler_proxy
204 # start-up failure.
205 goma_utils.UploadGomaCompilerProxyInfo(override_gsutil=override_gsutil)
206 # Upload GomaStats to make it monitored.
207 if env.get('GOMA_DUMP_STATS_FILE'):
208 goma_utils.SendGomaStats(env['GOMA_DUMP_STATS_FILE'],
209 env.get('GOMACTL_CRASH_REPORT_ID_FILE'),
210 options.build_data_dir)
211
212 if options.goma_disable_local_fallback:
213 print 'error: failed to start goma; fallback has been disabled'
214 raise Exception('failed to start goma')
215
216 print 'warning: failed to start goma. falling back to non-goma'
217 # Drop goma from options.compiler
218 options.compiler = options.compiler.replace('goma-', '')
219 if options.compiler == 'goma':
220 options.compiler = None
221 # Reset options.goma_dir.
222 options.goma_dir = None
223 env['GOMA_DISABLED'] = '1'
224 return False, None
225
226
227 # TODO(tikuta): move to goma_utils.py
228 def goma_teardown(options, env, exit_status, cloudtail_proc):
229 """Tears down goma if necessary. """
230 if (options.compiler in ('goma', 'goma-clang') and
231 options.goma_dir):
232 override_gsutil = None
233 if options.gsutil_py_path:
234 override_gsutil = [sys.executable, options.gsutil_py_path]
235
236 # If goma compiler_proxy crashes during the build, there could be crash
237 # dump.
238 if options.build_data_dir:
239 env['GOMACTL_CRASH_REPORT_ID_FILE'] = os.path.join(options.build_data_dir,
240 'crash_report_id_file')
241 goma_ctl_cmd = [sys.executable,
242 os.path.join(options.goma_dir, 'goma_ctl.py')]
243 if options.goma_jsonstatus:
244 chromium_utils.RunCommand(
245 goma_ctl_cmd + ['jsonstatus', options.goma_jsonstatus], env=env)
246 goma_utils.SendGomaTsMon(options.goma_jsonstatus, exit_status)
247 # Always stop the proxy for now to allow in-place update.
248 chromium_utils.RunCommand(goma_ctl_cmd + ['stop'], env=env)
249 goma_utils.UploadGomaCompilerProxyInfo(override_gsutil=override_gsutil)
250 if env.get('GOMA_DUMP_STATS_FILE'):
251 goma_utils.SendGomaStats(env['GOMA_DUMP_STATS_FILE'],
252 env.get('GOMACTL_CRASH_REPORT_ID_FILE'),
253 options.build_data_dir)
254 if cloudtail_proc:
255 cloudtail_proc.terminate()
256 cloudtail_proc.wait()
257
258
259 def maybe_set_official_build_envvars(options, env): 73 def maybe_set_official_build_envvars(options, env):
260 if options.mode == 'google_chrome' or options.mode == 'official': 74 if options.mode == 'google_chrome' or options.mode == 'official':
261 env['CHROMIUM_BUILD'] = '_google_chrome' 75 env['CHROMIUM_BUILD'] = '_google_chrome'
262 76
263 if options.mode == 'official': 77 if options.mode == 'official':
264 # Official builds are always Google Chrome. 78 # Official builds are always Google Chrome.
265 env['CHROME_BUILD_TYPE'] = '_official' 79 env['CHROME_BUILD_TYPE'] = '_official'
266 80
267 81
268 class EnsureUpToDateFilter(chromium_utils.RunCommandFilter): 82 class EnsureUpToDateFilter(chromium_utils.RunCommandFilter):
269 """Filter for RunCommand that checks whether the output contains ninja's 83 """Filter for RunCommand that checks whether the output contains ninja's
270 message for a no-op build.""" 84 message for a no-op build."""
271 def __init__(self): 85 def __init__(self):
272 self.was_up_to_date = False 86 self.was_up_to_date = False
273 87
274 def FilterLine(self, a_line): 88 def FilterLine(self, a_line):
275 if 'ninja: no work to do.' in a_line: 89 if 'ninja: no work to do.' in a_line:
276 self.was_up_to_date = True 90 self.was_up_to_date = True
277 return a_line 91 return a_line
278 92
279 93
280 def NeedEnvFileUpdateOnWin(env): 94 def NeedEnvFileUpdateOnWin(env):
ukai 2016/07/27 01:13:29 move it to goma_utils?
tikuta 2016/07/27 02:33:30 Done.
281 """Returns true if environment file need to be updated.""" 95 """Returns true if environment file need to be updated."""
282 # Following GOMA_* are applied to compiler_proxy not gomacc, 96 # Following GOMA_* are applied to compiler_proxy not gomacc,
283 # you do not need to update environment files. 97 # you do not need to update environment files.
284 ignore_envs = ( 98 ignore_envs = (
285 'GOMA_API_KEY_FILE', 99 'GOMA_API_KEY_FILE',
286 'GOMA_DEPS_CACHE_DIR', 100 'GOMA_DEPS_CACHE_DIR',
287 'GOMA_HERMETIC', 101 'GOMA_HERMETIC',
288 'GOMA_RPC_EXTRA_PARAMS', 102 'GOMA_RPC_EXTRA_PARAMS',
289 'GOMA_ALLOWED_NETWORK_ERROR_DURATION' 103 'GOMA_ALLOWED_NETWORK_ERROR_DURATION'
290 ) 104 )
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 if not entry: 154 if not entry:
341 continue 155 continue
342 key, value = entry.split('=', 1) 156 key, value = entry.split('=', 1)
343 env_in_file[key] = value 157 env_in_file[key] = value
344 env_in_file.update(env_to_store) 158 env_in_file.update(env_to_store)
345 with open(path, 'wb') as f: 159 with open(path, 'wb') as f:
346 f.write(nul.join(['%s=%s' % (k, v) for k, v in env_in_file.iteritems()])) 160 f.write(nul.join(['%s=%s' % (k, v) for k, v in env_in_file.iteritems()]))
347 f.write(nul * 2) 161 f.write(nul * 2)
348 162
349 163
350 # TODO(tikuta): move to goma_utils
351 def determine_goma_jobs():
352 # We would like to speed up build on Windows a bit, since it is slowest.
353 number_of_processors = 0
354 try:
355 number_of_processors = multiprocessing.cpu_count()
356 except NotImplementedError:
357 print 'cpu_count() is not implemented, using default value 50.'
358 return 50
359
360 assert number_of_processors > 0
361
362 # When goma is used, 10 * number_of_processors is basically good in
363 # various situations according to our measurement. Build speed won't
364 # be improved if -j is larger than that.
365 #
366 # Since Mac had process number limitation before, we had to set
367 # the upper limit to 50. Now that the process number limitation is 2000,
368 # so we would be able to use 10 * number_of_processors.
369 # For the safety, we'd like to set the upper limit to 200.
370 #
371 # Note that currently most try-bot build slaves have 8 processors.
372 if chromium_utils.IsMac() or chromium_utils.IsWindows():
373 return min(10 * number_of_processors, 200)
374
375 # For Linux, we also would like to use 10 * cpu. However, not sure
376 # backend resource is enough, so let me set Linux and Linux x64 builder
377 # only for now.
378 hostname = goma_utils.GetShortHostname()
379 if hostname in (
380 ['build14-m1', 'build48-m1'] +
381 # Also increasing cpus for v8/blink trybots.
382 ['build%d-m4' % x for x in xrange(45, 48)] +
383 # Also increasing cpus for LTO buildbots.
384 ['slave%d-c1' % x for x in [20, 33] + range(78, 108)]):
385 return min(10 * number_of_processors, 200)
386
387 return 50
388
389
390 def main_ninja(options, args, env): 164 def main_ninja(options, args, env):
391 """This function calls ninja. 165 """This function calls ninja.
392 166
393 Args: 167 Args:
394 options (Option): options for ninja command. 168 options (Option): options for ninja command.
395 args (str): extra args for ninja command. 169 args (str): extra args for ninja command.
396 env (dict): Used when ninja command executes. 170 env (dict): Used when ninja command executes.
397 171
398 Returns: 172 Returns:
399 int: ninja command exit status. 173 int: ninja command exit status.
400 174
401 """ 175 """
402 176
403 exit_status = -1 177 exit_status = -1
404 178
405 try: 179 try:
406 print 'chdir to %s' % options.src_dir 180 print 'chdir to %s' % options.src_dir
407 os.chdir(options.src_dir) 181 os.chdir(options.src_dir)
408 182
409 command = [options.ninja_path, '-w', 'dupbuild=err', 183 command = [options.ninja_path, '-w', 'dupbuild=err',
410 '-C', options.target_output_dir] 184 '-C', options.target_output_dir]
411 185
412 # HACK(yyanagisawa): update environment files on |env| update. 186 # HACK(yyanagisawa): update environment files on |env| update.
ukai 2016/07/27 01:13:29 might be goma specific (part of goma_setup)?
tikuta 2016/07/27 02:33:30 Done.
413 # For compiling on Windows, environment in environment files are used. 187 # For compiling on Windows, environment in environment files are used.
414 # It means even if enviroment such as GOMA_DISABLED is updated in 188 # It means even if enviroment such as GOMA_DISABLED is updated in
415 # compile.py, the update will be ignored. 189 # compile.py, the update will be ignored.
416 # We need to update environment files to reflect the update. 190 # We need to update environment files to reflect the update.
417 if chromium_utils.IsWindows() and NeedEnvFileUpdateOnWin(env): 191 if chromium_utils.IsWindows() and NeedEnvFileUpdateOnWin(env):
418 print 'Updating environment.{x86,x64} files.' 192 print 'Updating environment.{x86,x64} files.'
419 UpdateWindowsEnvironment(options.target_output_dir, env) 193 UpdateWindowsEnvironment(options.target_output_dir, env)
420 194
421 if options.clobber: 195 if options.clobber:
422 print 'Removing %s' % options.target_output_dir 196 print 'Removing %s' % options.target_output_dir
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 return options, args 327 return options, args
554 328
555 329
556 def real_main(): 330 def real_main():
557 options, args = get_parsed_options() 331 options, args = get_parsed_options()
558 332
559 # Prepare environment. 333 # Prepare environment.
560 env = EchoDict(os.environ) 334 env = EchoDict(os.environ)
561 335
562 # start goma 336 # start goma
563 goma_ready, goma_cloudtail = goma_setup(options, env) 337 goma_ready, goma_cloudtail = goma_utils.goma_setup(options, env)
564 338
565 if not goma_ready: 339 if not goma_ready:
ukai 2016/07/27 01:13:29 if goma_ready: if options.goma_jobs is None:
tikuta 2016/07/27 02:33:30 Done.
566 assert options.compiler not in ('goma', 'goma-clang') 340 assert options.compiler not in ('goma', 'goma-clang')
567 assert options.goma_dir is None 341 assert options.goma_dir is None
568 elif options.goma_jobs is None: 342 elif options.goma_jobs is None:
569 options.goma_jobs = determine_goma_jobs() 343 options.goma_jobs = goma_utils.determine_goma_jobs()
570 344
571 # build 345 # build
572 exit_status = main_ninja(options, args, env) 346 exit_status = main_ninja(options, args, env)
573 347
574 # stop goma 348 # stop goma
575 goma_teardown(options, env, exit_status, goma_cloudtail) 349 goma_utils.goma_teardown(options, env, exit_status, goma_cloudtail)
576 350
577 return exit_status 351 return exit_status
578 352
579 353
580 if '__main__' == __name__: 354 if '__main__' == __name__:
581 sys.exit(real_main()) 355 sys.exit(real_main())
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/goma_utils.py » ('j') | scripts/slave/goma_utils.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698