Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 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 """Functions specific to handle goma related info. | 5 """Functions specific to handle goma related info. |
| 6 """ | 6 """ |
| 7 | 7 |
| 8 import base64 | 8 import base64 |
| 9 import datetime | 9 import datetime |
| 10 import getpass | 10 import getpass |
| 11 import glob | 11 import glob |
| 12 import gzip | 12 import gzip |
| 13 import json | 13 import json |
| 14 import multiprocessing | |
| 14 import os | 15 import os |
| 15 import re | 16 import re |
| 16 import shutil | 17 import shutil |
| 17 import socket | 18 import socket |
| 19 import subprocess | |
| 18 import sys | 20 import sys |
| 19 import tempfile | 21 import tempfile |
| 20 import time | 22 import time |
| 21 | 23 |
| 22 from common import chromium_utils | 24 from common import chromium_utils |
| 23 from slave import slave_utils | 25 from slave import slave_utils |
| 24 | 26 |
| 25 # The Google Cloud Storage bucket to store logs related to goma. | 27 # The Google Cloud Storage bucket to store logs related to goma. |
| 26 GOMA_LOG_GS_BUCKET = 'chrome-goma-log' | 28 GOMA_LOG_GS_BUCKET = 'chrome-goma-log' |
| 27 | 29 |
| 28 # Platform dependent location of run command. | 30 # Platform dependent location of run command. |
| 29 PLATFORM_RUN_CMD = { | 31 PLATFORM_RUN_CMD = { |
| 30 # os.name: run_cmd to use. | 32 # os.name: run_cmd to use. |
| 31 'nt': 'C:\\infra-python\\run.py', | 33 'nt': 'C:\\infra-python\\run.py', |
| 32 'posix': '/opt/infra-python/run.py', | 34 'posix': '/opt/infra-python/run.py', |
| 33 } | 35 } |
| 34 | 36 |
| 35 TIMESTAMP_PATTERN = re.compile('(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})') | 37 TIMESTAMP_PATTERN = re.compile('(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})') |
| 36 TIMESTAMP_FORMAT = '%Y/%m/%d %H:%M:%S' | 38 TIMESTAMP_FORMAT = '%Y/%m/%d %H:%M:%S' |
| 37 | 39 |
| 40 # Define a bunch of directory paths (same as bot_update.py) | |
| 41 CURRENT_DIR = os.path.abspath(os.getcwd()) | |
| 42 BUILDER_DIR = os.path.dirname(CURRENT_DIR) | |
| 43 SLAVE_DIR = os.path.dirname(BUILDER_DIR) | |
| 44 # GOMA_CACHE_DIR used for caching long-term data. | |
| 45 DEFAULT_GOMA_CACHE_DIR = os.path.join(SLAVE_DIR, 'goma_cache') | |
| 46 | |
| 47 | |
| 38 | 48 |
| 39 def GetShortHostname(): | 49 def GetShortHostname(): |
| 40 """Get this machine's short hostname in lower case.""" | 50 """Get this machine's short hostname in lower case.""" |
| 41 return socket.gethostname().split('.')[0].lower() | 51 return socket.gethostname().split('.')[0].lower() |
| 42 | 52 |
| 43 | 53 |
| 44 def GetGomaTmpDirectory(): | 54 def GetGomaTmpDirectory(): |
| 45 """Get goma's temp directory.""" | 55 """Get goma's temp directory.""" |
| 46 candidates = ['GOMA_TMP_DIR', 'TEST_TMPDIR', 'TMPDIR', 'TMP'] | 56 candidates = ['GOMA_TMP_DIR', 'TEST_TMPDIR', 'TMPDIR', 'TMP'] |
| 47 for candidate in candidates: | 57 for candidate in candidates: |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 retcode = chromium_utils.RunCommand( | 358 retcode = chromium_utils.RunCommand( |
| 349 cmd, filter_obj=cmd_filter, | 359 cmd, filter_obj=cmd_filter, |
| 350 max_time=30) | 360 max_time=30) |
| 351 if retcode: | 361 if retcode: |
| 352 print('Execution of send_ts_mon_values failed with code %s' | 362 print('Execution of send_ts_mon_values failed with code %s' |
| 353 % retcode) | 363 % retcode) |
| 354 print '\n'.join(cmd_filter.text) | 364 print '\n'.join(cmd_filter.text) |
| 355 | 365 |
| 356 except Exception as ex: | 366 except Exception as ex: |
| 357 print('error while sending ts mon json_file=%s: %s' % (json_file, ex)) | 367 print('error while sending ts mon json_file=%s: %s' % (json_file, ex)) |
| 368 | |
| 369 | |
| 370 def goma_setup(options, env): | |
|
Yoshisato Yanagisawa
2016/07/27 02:54:46
options is data structure made in compile.py, why
| |
| 371 """Sets up goma if necessary. | |
| 372 | |
| 373 If using the Goma compiler, first call goma_ctl to ensure the proxy is | |
| 374 available, and returns (True, instance of cloudtail subprocess). | |
| 375 If it failed to start up compiler_proxy, modify options.compiler and | |
| 376 options.goma_dir and returns (False, None) | |
| 377 | |
| 378 Args: | |
| 379 options (Option): options for goma | |
| 380 env (dict): env for compiler_proxy | |
| 381 | |
| 382 Returns: | |
| 383 (bool, subprocess.Popen): | |
| 384 first element represents whether compiler_proxy starts successfully | |
| 385 second element is subprocess instance of cloudtail | |
| 386 | |
| 387 """ | |
| 388 if options.compiler not in ('goma', 'goma-clang'): | |
| 389 # Unset goma_dir to make sure we'll not use goma. | |
| 390 options.goma_dir = None | |
| 391 return False, None | |
| 392 | |
| 393 hostname = GetShortHostname() | |
| 394 # HACK(shinyak, yyanagisawa, goma): Windows NO_NACL_GOMA (crbug.com/390764) | |
|
Yoshisato Yanagisawa
2016/07/27 02:54:46
Can you remove this HACK, and injected from compil
ukai
2016/07/27 06:52:54
do we still need this hack?
Yoshisato Yanagisawa
2016/07/27 07:02:31
I do not think so.
I feel a bit guilty but I feel
| |
| 395 # Building NaCl untrusted code using goma brings large performance | |
| 396 # improvement but it sometimes cause build failure by race condition. | |
| 397 # Let me enable goma build on goma canary buildslaves to confirm the issue | |
| 398 # has been fixed by a workaround. | |
| 399 # vm*-m4 are trybots. build*-m1 and vm*-m1 are all goma canary bots. | |
| 400 if hostname in ['build28-m1', 'build58-m1', 'vm191-m1', 'vm480-m1', | |
| 401 'vm820-m1', 'vm821-m1', 'vm848-m1']: | |
| 402 env['NO_NACL_GOMA'] = 'false' | |
| 403 | |
| 404 if options.goma_fail_fast: | |
| 405 # startup fails when initial ping failed. | |
| 406 env['GOMA_FAIL_FAST'] = 'true' | |
| 407 else: | |
| 408 # If a network error continues 30 minutes, compiler_proxy make the compile | |
| 409 # failed. When people use goma, they expect using goma is faster than | |
| 410 # compile locally. If goma cannot guarantee that, let it make compile | |
| 411 # as error. | |
| 412 env['GOMA_ALLOWED_NETWORK_ERROR_DURATION'] = '1800' | |
| 413 | |
| 414 # HACK(yyanagisawa): reduce GOMA_BURST_MAX_PROCS crbug.com/592306 | |
| 415 # Recently, I sometimes see buildbot slave time out, one possibility I come | |
| 416 # up with is burst mode use up resource. | |
| 417 # Let me temporary set small values to GOMA_BURST_MAX_PROCS to confirm | |
| 418 # the possibility is true or false. | |
| 419 max_subprocs = '3' | |
| 420 max_heavy_subprocs = '1' | |
| 421 number_of_processors = 0 | |
| 422 try: | |
| 423 number_of_processors = multiprocessing.cpu_count() | |
| 424 except NotImplementedError: | |
| 425 print 'cpu_count() is not implemented, using default value.' | |
| 426 number_of_processors = 1 | |
| 427 if number_of_processors > 3: | |
| 428 max_subprocs = str(number_of_processors - 1) | |
| 429 max_heavy_subprocs = str(number_of_processors / 2) | |
| 430 env['GOMA_BURST_MAX_SUBPROCS'] = max_subprocs | |
| 431 env['GOMA_BURST_MAX_SUBPROCS_LOW'] = max_subprocs | |
| 432 env['GOMA_BURST_MAX_SUBPROCS_HEAVY'] = max_heavy_subprocs | |
| 433 | |
| 434 # Caches CRLs in GOMA_CACHE_DIR. | |
| 435 # Since downloading CRLs is usually slow, caching them may improves | |
| 436 # compiler_proxy start time. | |
| 437 if not os.path.exists(options.goma_cache_dir): | |
| 438 os.mkdir(options.goma_cache_dir, 0700) | |
| 439 env['GOMA_CACHE_DIR'] = options.goma_cache_dir | |
| 440 | |
| 441 # Enable DepsCache. DepsCache caches the list of files to send goma server. | |
| 442 # This will greatly improve build speed when cache is warmed. | |
| 443 # The cache file is stored in the target output directory. | |
| 444 env['GOMA_DEPS_CACHE_DIR'] = ( | |
| 445 options.goma_deps_cache_dir or options.target_output_dir) | |
| 446 | |
| 447 if not env.get('GOMA_HERMETIC'): | |
| 448 env['GOMA_HERMETIC'] = options.goma_hermetic | |
| 449 if options.goma_enable_remote_link: | |
| 450 env['GOMA_ENABLE_REMOTE_LINK'] = options.goma_enable_remote_link | |
| 451 if options.goma_store_local_run_output: | |
| 452 env['GOMA_STORE_LOCAL_RUN_OUTPUT'] = options.goma_store_local_run_output | |
| 453 if options.goma_enable_compiler_info_cache: | |
| 454 # Will be stored in GOMA_CACHE_DIR. | |
| 455 env['GOMA_COMPILER_INFO_CACHE_FILE'] = 'goma-compiler-info.cache' | |
| 456 | |
| 457 if options.build_data_dir: | |
| 458 env['GOMA_DUMP_STATS_FILE'] = os.path.join(options.build_data_dir, | |
| 459 'goma_stats_proto') | |
| 460 | |
| 461 # goma is requested. | |
| 462 goma_key = os.path.join(options.goma_dir, 'goma.key') | |
| 463 if os.path.exists(goma_key): | |
| 464 env['GOMA_API_KEY_FILE'] = goma_key | |
| 465 if options.goma_service_account_json_file: | |
| 466 env['GOMA_SERVICE_ACCOUNT_JSON_FILE'] = \ | |
| 467 options.goma_service_account_json_file | |
| 468 if chromium_utils.IsWindows(): | |
| 469 env['GOMA_RPC_EXTRA_PARAMS'] = '?win' | |
| 470 | |
| 471 # HACK(yyanagisawa): update environment files on |env| update. | |
| 472 # For compiling on Windows, environment in environment files are used. | |
| 473 # It means even if enviroment such as GOMA_DISABLED is updated in | |
| 474 # compile.py, the update will be ignored. | |
| 475 # We need to update environment files to reflect the update. | |
| 476 if chromium_utils.IsWindows() and NeedEnvFileUpdateOnWin(env): | |
| 477 print 'Updating environment.{x86,x64} files.' | |
| 478 UpdateWindowsEnvironment(options.target_output_dir, env) | |
| 479 | |
| 480 | |
| 481 goma_start_command = ['restart'] | |
| 482 goma_ctl_cmd = [sys.executable, | |
| 483 os.path.join(options.goma_dir, 'goma_ctl.py')] | |
| 484 result = chromium_utils.RunCommand(goma_ctl_cmd + goma_start_command, env=env) | |
| 485 if not result: | |
| 486 # goma started sucessfully. | |
| 487 # Making cloudtail to upload the latest log. | |
| 488 # TODO(yyanagisawa): install cloudtail from CIPD. | |
| 489 cloudtail_path = '/opt/infra-tools/cloudtail' | |
| 490 if chromium_utils.IsWindows(): | |
| 491 cloudtail_path = 'C:\\infra-tools\\cloudtail' | |
| 492 try: | |
| 493 cloudtail_proc = subprocess.Popen( | |
| 494 [cloudtail_path, 'tail', '--log-id', 'goma_compiler_proxy', '--path', | |
| 495 GetLatestGomaCompilerProxyInfo()]) | |
| 496 except Exception as e: | |
| 497 print 'failed to invoke cloudtail: %s' % e | |
| 498 return True, None | |
| 499 return True, cloudtail_proc | |
| 500 | |
| 501 if options.goma_jsonstatus: | |
| 502 chromium_utils.RunCommand( | |
| 503 goma_ctl_cmd + ['jsonstatus', options.goma_jsonstatus], env=env) | |
| 504 SendGomaTsMon(options.goma_jsonstatus, -1) | |
| 505 | |
| 506 # Try to stop compiler_proxy so that it flushes logs and stores | |
| 507 # GomaStats. | |
| 508 if options.build_data_dir: | |
| 509 env['GOMACTL_CRASH_REPORT_ID_FILE'] = os.path.join(options.build_data_dir, | |
| 510 'crash_report_id_file') | |
| 511 chromium_utils.RunCommand(goma_ctl_cmd + ['stop'], env=env) | |
| 512 | |
| 513 override_gsutil = None | |
| 514 if options.gsutil_py_path: | |
| 515 override_gsutil = [sys.executable, options.gsutil_py_path] | |
| 516 | |
| 517 # Upload compiler_proxy.INFO to investigate the reason of compiler_proxy | |
| 518 # start-up failure. | |
| 519 UploadGomaCompilerProxyInfo(override_gsutil=override_gsutil) | |
| 520 # Upload GomaStats to make it monitored. | |
| 521 if env.get('GOMA_DUMP_STATS_FILE'): | |
| 522 SendGomaStats(env['GOMA_DUMP_STATS_FILE'], | |
| 523 env.get('GOMACTL_CRASH_REPORT_ID_FILE'), | |
| 524 options.build_data_dir) | |
| 525 | |
| 526 if options.goma_disable_local_fallback: | |
| 527 print 'error: failed to start goma; fallback has been disabled' | |
| 528 raise Exception('failed to start goma') | |
| 529 | |
| 530 print 'warning: failed to start goma. falling back to non-goma' | |
| 531 # Drop goma from options.compiler | |
| 532 options.compiler = options.compiler.replace('goma-', '') | |
| 533 if options.compiler == 'goma': | |
| 534 options.compiler = None | |
| 535 # Reset options.goma_dir. | |
| 536 options.goma_dir = None | |
| 537 env['GOMA_DISABLED'] = '1' | |
| 538 return False, None | |
| 539 | |
| 540 | |
| 541 def goma_teardown(options, env, exit_status, cloudtail_proc): | |
|
Yoshisato Yanagisawa
2016/07/27 02:54:47
The same, is it impossible for you to eliminate de
| |
| 542 """Tears down goma if necessary. """ | |
| 543 if (options.compiler in ('goma', 'goma-clang') and | |
| 544 options.goma_dir): | |
| 545 override_gsutil = None | |
| 546 if options.gsutil_py_path: | |
| 547 override_gsutil = [sys.executable, options.gsutil_py_path] | |
| 548 | |
| 549 # If goma compiler_proxy crashes during the build, there could be crash | |
| 550 # dump. | |
| 551 if options.build_data_dir: | |
| 552 env['GOMACTL_CRASH_REPORT_ID_FILE'] = os.path.join(options.build_data_dir, | |
| 553 'crash_report_id_file') | |
| 554 goma_ctl_cmd = [sys.executable, | |
| 555 os.path.join(options.goma_dir, 'goma_ctl.py')] | |
| 556 if options.goma_jsonstatus: | |
| 557 chromium_utils.RunCommand( | |
| 558 goma_ctl_cmd + ['jsonstatus', options.goma_jsonstatus], env=env) | |
| 559 SendGomaTsMon(options.goma_jsonstatus, exit_status) | |
| 560 # Always stop the proxy for now to allow in-place update. | |
| 561 chromium_utils.RunCommand(goma_ctl_cmd + ['stop'], env=env) | |
| 562 UploadGomaCompilerProxyInfo(override_gsutil=override_gsutil) | |
| 563 if env.get('GOMA_DUMP_STATS_FILE'): | |
| 564 SendGomaStats(env['GOMA_DUMP_STATS_FILE'], | |
| 565 env.get('GOMACTL_CRASH_REPORT_ID_FILE'), | |
| 566 options.build_data_dir) | |
| 567 if cloudtail_proc: | |
| 568 cloudtail_proc.terminate() | |
| 569 cloudtail_proc.wait() | |
| 570 | |
| 571 | |
| 572 def determine_goma_jobs(): | |
| 573 # We would like to speed up build on Windows a bit, since it is slowest. | |
| 574 number_of_processors = 0 | |
| 575 try: | |
| 576 number_of_processors = multiprocessing.cpu_count() | |
| 577 except NotImplementedError: | |
| 578 print 'cpu_count() is not implemented, using default value 50.' | |
| 579 return 50 | |
| 580 | |
| 581 assert number_of_processors > 0 | |
| 582 | |
| 583 # When goma is used, 10 * number_of_processors is basically good in | |
| 584 # various situations according to our measurement. Build speed won't | |
| 585 # be improved if -j is larger than that. | |
| 586 # | |
| 587 # Since Mac had process number limitation before, we had to set | |
| 588 # the upper limit to 50. Now that the process number limitation is 2000, | |
| 589 # so we would be able to use 10 * number_of_processors. | |
| 590 # For the safety, we'd like to set the upper limit to 200. | |
| 591 # | |
| 592 # Note that currently most try-bot build slaves have 8 processors. | |
| 593 if chromium_utils.IsMac() or chromium_utils.IsWindows(): | |
| 594 return min(10 * number_of_processors, 200) | |
| 595 | |
| 596 # For Linux, we also would like to use 10 * cpu. However, not sure | |
| 597 # backend resource is enough, so let me set Linux and Linux x64 builder | |
| 598 # only for now. | |
| 599 hostname = GetShortHostname() | |
| 600 if hostname in ( | |
| 601 ['build14-m1', 'build48-m1'] + | |
| 602 # Also increasing cpus for v8/blink trybots. | |
| 603 ['build%d-m4' % x for x in xrange(45, 48)] + | |
| 604 # Also increasing cpus for LTO buildbots. | |
| 605 ['slave%d-c1' % x for x in [20, 33] + range(78, 108)]): | |
| 606 return min(10 * number_of_processors, 200) | |
| 607 | |
| 608 return 50 | |
| 609 | |
| 610 | |
| 611 def NeedEnvFileUpdateOnWin(env): | |
| 612 """Returns true if environment file need to be updated.""" | |
| 613 # Following GOMA_* are applied to compiler_proxy not gomacc, | |
| 614 # you do not need to update environment files. | |
| 615 ignore_envs = ( | |
| 616 'GOMA_API_KEY_FILE', | |
| 617 'GOMA_DEPS_CACHE_DIR', | |
| 618 'GOMA_HERMETIC', | |
| 619 'GOMA_RPC_EXTRA_PARAMS', | |
| 620 'GOMA_ALLOWED_NETWORK_ERROR_DURATION' | |
| 621 ) | |
| 622 for key in env.overrides: | |
| 623 if key not in ignore_envs: | |
| 624 return True | |
| 625 return False | |
| OLD | NEW |