1336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org#!/usr/bin/env python 2336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org 3336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org 4336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org# Copyright (c) 2014 The Chromium Authors. All rights reserved. 5336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org# Use of this source code is governed by a BSD-style license that can be 6336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org# found in the LICENSE file. 7336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org 85ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 95ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org"""greenify.py: standalone script to correct flaky bench expectations. 10336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org 11336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org Requires Rietveld credentials on the running machine. 12336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org 13336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org Usage: 14336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org Copy script to a separate dir outside Skia repo. The script will create a 15336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org skia dir on the first run to host the repo, and will create/delete 16336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org temp dirs as needed. 17336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org ./greenify.py --url <the stdio url from failed CheckForRegressions step> 185ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org""" 195ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 205ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport argparse 215ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport filecmp 225ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport os 235ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport re 245ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport shutil 255ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport subprocess 265ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport time 275ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgimport urllib2 285ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 295ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 305ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org# Regular expression for matching exception data. 315ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgEXCEPTION_RE = ('Bench (\S+) out of range \[(\d+.\d+), (\d+.\d+)\] \((\d+.\d+) ' 325ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 'vs (\d+.\d+), ') 335ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgEXCEPTION_RE_COMPILED = re.compile(EXCEPTION_RE) 345ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 355ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 365ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgdef clean_dir(d): 375ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if os.path.exists(d): 385ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org shutil.rmtree(d) 395ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.makedirs(d) 405ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 415ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgdef checkout_or_update_skia(repo_dir): 425ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org status = True 435ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org old_cwd = os.getcwd() 445ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(repo_dir) 455ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'CHECK SKIA REPO...' 465ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if subprocess.call(['git', 'pull'], 475ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org stderr=subprocess.PIPE): 485ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'Checking out Skia from git, please be patient...' 495ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(old_cwd) 505ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org clean_dir(repo_dir) 515ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(repo_dir) 525ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if subprocess.call(['git', 'clone', '-q', '--depth=50', '--single-branch', 535ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 'https://skia.googlesource.com/skia.git', '.']): 545ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org status = False 555ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org subprocess.call(['git', 'checkout', 'master']) 565ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org subprocess.call(['git', 'pull']) 575ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(old_cwd) 585ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return status 595ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 605ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgdef git_commit_expectations(repo_dir, exp_dir, bot, build, commit): 615ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org commit_msg = """Greenify bench bot %s at build %s 625ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 6377767358a3e26693282f9958df6c64df68b65676commit-bot@chromium.orgTBR=bsalomon@google.com 645ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 6577767358a3e26693282f9958df6c64df68b65676commit-bot@chromium.orgBypassing trybots: 6677767358a3e26693282f9958df6c64df68b65676commit-bot@chromium.orgNOTRY=true""" % (bot, build) 675ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org old_cwd = os.getcwd() 685ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(repo_dir) 695ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org upload = ['git', 'cl', 'upload', '-f', '--bypass-hooks', 705ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org '--bypass-watchlists', '-m', commit_msg] 715ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if commit: 725ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org upload.append('--use-commit-queue') 735ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org branch = exp_dir[exp_dir.rfind('/') + 1:] 745ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org filename = 'bench_expectations_%s.txt' % bot 755ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org cmds = ([['git', 'checkout', 'master'], 765ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['git', 'pull'], 775ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['git', 'checkout', '-b', branch, '-t', 'origin/master'], 785ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['cp', '%s/%s' % (exp_dir, filename), 'expectations/bench'], 795ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['git', 'add', 'expectations/bench/' + filename], 805ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['git', 'commit', '-m', commit_msg], 815ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org upload, 825ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['git', 'checkout', 'master'], 835ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ['git', 'branch', '-D', branch], 845ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ]) 855ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org status = True 865ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org for cmd in cmds: 875ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'Running ' + ' '.join(cmd) 885ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if subprocess.call(cmd): 895ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'FAILED. Please check if skia git repo is present.' 905ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org subprocess.call(['git', 'checkout', 'master']) 915ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org status = False 925ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org break 935ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(old_cwd) 945ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return status 955ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 965ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgdef delete_dirs(li): 975ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org for d in li: 985ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'Deleting directory %s' % d 995ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org shutil.rmtree(d) 1005ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1015ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgdef widen_bench_ranges(url, bot, repo_dir, exp_dir): 1025ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org fname = 'bench_expectations_%s.txt' % bot 1035ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org src = os.path.join(repo_dir, 'expectations', 'bench', fname) 1045ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not os.path.isfile(src): 1055ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'This bot has no expectations! %s' % bot 1065ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return False 1075ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org row_dic = {} 1085ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org for l in urllib2.urlopen(url).read().split('\n'): 1095ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org data = EXCEPTION_RE_COMPILED.search(l) 1105ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if data: 1115ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org row = data.group(1) 1125ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org lb = float(data.group(2)) 1135ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ub = float(data.group(3)) 1145ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org actual = float(data.group(4)) 1155ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org exp = float(data.group(5)) 1165ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org avg = (actual + exp) / 2 1175ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org shift = avg - exp 1185ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org lb = lb + shift 1195ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ub = ub + shift 1205ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org # In case outlier really fluctuates a lot 1215ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if actual < lb: 1225ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org lb = actual - abs(shift) * 0.1 + 0.5 1235ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org elif actual > ub: 1245ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ub = actual + abs(shift) * 0.1 + 0.5 1255ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org row_dic[row] = '%.2f,%.2f,%.2f' % (avg, lb, ub) 1265ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not row_dic: 1275ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'NO out-of-range benches found at %s' % url 1285ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return False 1295ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1305ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org changed = 0 1315ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org li = [] 1325ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org for l in open(src).readlines(): 1335ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org parts = l.strip().split(',') 1345ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if parts[0].startswith('#') or len(parts) != 5: 1355ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org li.append(l.strip()) 1365ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org continue 1375ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if ','.join(parts[:2]) in row_dic: 1385ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org li.append(','.join(parts[:2]) + ',' + row_dic[','.join(parts[:2])]) 1395ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org changed += 1 1405ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org else: 1415ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org li.append(l.strip()) 1425ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not changed: 1435ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'Not in source file:\n' + '\n'.join(row_dic.keys()) 1445ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return False 1455ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1465ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org dst = os.path.join(exp_dir, fname) 1475ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org with open(dst, 'w+') as f: 1485ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org f.write('\n'.join(li)) 1495ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return True 1505ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1515ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1525ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgdef main(): 1535ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org d = os.path.dirname(os.path.abspath(__file__)) 1545ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.chdir(d) 1555ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not subprocess.call(['git', 'rev-parse'], stderr=subprocess.PIPE): 1565ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'Please copy script to a separate dir outside git repos to use.' 1575ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return 1585ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org ts_str = '%s' % time.time() 1595ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1605ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org parser = argparse.ArgumentParser() 1615ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org parser.add_argument('--url', 1625ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org help='Broken bench build CheckForRegressions page url.') 1635ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org parser.add_argument('--commit', action='store_true', 1645ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org help='Whether to commit changes automatically.') 1655ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org args = parser.parse_args() 1665ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org repo_dir = os.path.join(d, 'skia') 1675ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not os.path.exists(repo_dir): 1685ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org os.makedirs(repo_dir) 1695ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not checkout_or_update_skia(repo_dir): 1705ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'ERROR setting up Skia repo at %s' % repo_dir 1715ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return 1 1725ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1735ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org file_in_repo = os.path.join(d, 'skia/experimental/benchtools/greenify.py') 1745ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not filecmp.cmp(__file__, file_in_repo): 1755ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org shutil.copy(file_in_repo, __file__) 1765ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'Updated this script from repo; please run again.' 1775ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org return 1785ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 1795ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not args.url: 1805ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org raise Exception('Please provide a url with broken CheckForRegressions.') 1815ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org path = args.url.split('/') 1825ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if len(path) != 11 or not path[6].isdigit(): 1835ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org raise Exception('Unexpected url format: %s' % args.url) 1845ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org bot = path[4] 1855ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org build = path[6] 1865ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org commit = False 1875ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if args.commit: 1885ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org commit = True 1895ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 190336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org exp_dir = os.path.join(d, 'exp' + ts_str) 191336df8fd3494af14fa00c759578f9845fc0ec4b3commit-bot@chromium.org clean_dir(exp_dir) 1925ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org if not widen_bench_ranges(args.url, bot, repo_dir, exp_dir): 1935ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'NO bench exceptions found! %s' % args.url 1945ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org elif not git_commit_expectations( 1955ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org repo_dir, exp_dir, bot, build, commit): 1965ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'ERROR uploading expectations using git.' 1975ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org elif not commit: 1985ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'CL created. Please take a look at the link above.' 1995ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org else: 2005ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org print 'New bench baselines should be in CQ now.' 2015ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org delete_dirs([exp_dir]) 2025ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 2035ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org 2045ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.orgif __name__ == "__main__": 2055ddea761a97d7ab41eecff630b602297ce7299d4commit-bot@chromium.org main() 206