OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python2.7 |
| 2 |
| 3 """rebase.py: standalone script to batch update bench expectations. |
| 4 Usage: |
| 5 Copy script to a separate dir outside Skia repo. The script will create a |
| 6 skia dir on the first run to host the repo, and will create/delete temp |
| 7 dirs as needed. |
| 8 ./rebase.py --githash <githash prefix to use for getting bench data> |
| 9 """ |
| 10 |
| 11 import argparse |
| 12 import filecmp |
| 13 import os |
| 14 import re |
| 15 import shutil |
| 16 import subprocess |
| 17 import time |
| 18 import urllib2 |
| 19 |
| 20 |
| 21 # googlesource url that has most recent Skia git hash info. |
| 22 SKIA_GIT_HEAD_URL = 'https://skia.googlesource.com/skia/+log/HEAD' |
| 23 |
| 24 # Google Storage bench file prefix. |
| 25 GS_PREFIX = 'gs://chromium-skia-gm/perfdata' |
| 26 |
| 27 # List of Perf platforms we want to process. Populate from expectations/bench. |
| 28 PLATFORMS = [] |
| 29 |
| 30 # Regular expression for matching githash data. |
| 31 HA_RE = '<a href="/skia/\+/([0-9a-f]+)">' |
| 32 HA_RE_COMPILED = re.compile(HA_RE) |
| 33 |
| 34 |
| 35 def get_git_hashes(): |
| 36 print 'Getting recent git hashes...' |
| 37 hashes = HA_RE_COMPILED.findall( |
| 38 urllib2.urlopen(SKIA_GIT_HEAD_URL).read()) |
| 39 |
| 40 return hashes |
| 41 |
| 42 def filter_file(f): |
| 43 if f.find('_msaa') > 0 or f.find('_record') > 0: |
| 44 return True |
| 45 |
| 46 return False |
| 47 |
| 48 def clean_dir(d): |
| 49 if os.path.exists(d): |
| 50 shutil.rmtree(d) |
| 51 os.makedirs(d) |
| 52 |
| 53 def get_gs_filelist(p, h): |
| 54 print 'Looking up for the closest bench files in Google Storage...' |
| 55 proc = subprocess.Popen(['gsutil', 'ls', |
| 56 '/'.join([GS_PREFIX, p, 'bench_' + h + '_data_skp_*'])], |
| 57 stdout=subprocess.PIPE) |
| 58 out, err = proc.communicate() |
| 59 if err or not out: |
| 60 return [] |
| 61 return [i for i in out.strip().split('\n') if not filter_file(i)] |
| 62 |
| 63 def download_gs_files(p, h, gs_dir): |
| 64 print 'Downloading raw bench files from Google Storage...' |
| 65 proc = subprocess.Popen(['gsutil', '-q', 'cp', |
| 66 '/'.join([GS_PREFIX, p, 'bench_' + h + '_data_skp_*']), |
| 67 '%s/%s' % (gs_dir, p)], |
| 68 stdout=subprocess.PIPE) |
| 69 out, err = proc.communicate() |
| 70 if err: |
| 71 clean_dir(gs_dir) |
| 72 return False |
| 73 files = 0 |
| 74 for f in os.listdir(os.path.join(gs_dir, p)): |
| 75 if filter_file(f): |
| 76 os.remove(os.path.join(gs_dir, p, f)) |
| 77 else: |
| 78 files += 1 |
| 79 if files == 4: |
| 80 return True |
| 81 return False |
| 82 |
| 83 def calc_expectations(p, h, gs_dir, exp_dir, repo_dir): |
| 84 exp_filename = 'bench_expectations_%s.txt' % p |
| 85 proc = subprocess.Popen(['python', 'skia/bench/gen_bench_expectations.py', |
| 86 '-r', h, '-b', p, '-d', os.path.join(gs_dir, p), '-o', |
| 87 os.path.join(exp_dir, exp_filename)], |
| 88 stdout=subprocess.PIPE) |
| 89 out, err = proc.communicate() |
| 90 if err: |
| 91 print 'ERR_CALCULATING_EXPECTATIONS: ' + err |
| 92 return False |
| 93 print 'CALCULATED_EXPECTATIONS: ' + out |
| 94 repo_file = os.path.join(repo_dir, 'expectations', 'bench', exp_filename) |
| 95 if (os.path.isfile(repo_file) and |
| 96 filecmp.cmp(repo_file, os.path.join(exp_dir, exp_filename))): |
| 97 print 'NO CHANGE ON %s' % repo_file |
| 98 return False |
| 99 return True |
| 100 |
| 101 def checkout_or_update_skia(repo_dir): |
| 102 status = True |
| 103 old_cwd = os.getcwd() |
| 104 os.chdir(repo_dir) |
| 105 print 'CHECK SKIA REPO...' |
| 106 if subprocess.call(['git', 'pull'], |
| 107 stderr=subprocess.PIPE): |
| 108 print 'Checking out Skia from git, please be patient...' |
| 109 os.chdir(old_cwd) |
| 110 clean_dir(repo_dir) |
| 111 os.chdir(repo_dir) |
| 112 if subprocess.call(['git', 'clone', '-q', '--depth=50', '--single-branch', |
| 113 'https://skia.googlesource.com/skia.git', '.']): |
| 114 status = False |
| 115 subprocess.call(['git', 'checkout', 'master']) |
| 116 subprocess.call(['git', 'pull']) |
| 117 os.chdir(old_cwd) |
| 118 return status |
| 119 |
| 120 def git_commit_expectations(repo_dir, exp_dir, update_li, h, commit): |
| 121 commit_msg = """bench rebase after %s |
| 122 |
| 123 TBR=robertphillips@google.com |
| 124 |
| 125 Bypassing trybots: |
| 126 NOTRY=true""" % h |
| 127 old_cwd = os.getcwd() |
| 128 os.chdir(repo_dir) |
| 129 upload = ['git', 'cl', 'upload', '-f', '--bypass-hooks', |
| 130 '--bypass-watchlists', '-m', commit_msg] |
| 131 if commit: |
| 132 upload.append('--use-commit-queue') |
| 133 cmds = ([['git', 'checkout', 'master'], |
| 134 ['git', 'pull'], |
| 135 ['git', 'checkout', '-b', exp_dir, '-t', 'origin/master']] + |
| 136 [['cp', '../%s/%s' % (exp_dir, f), 'expectations/bench'] for f in |
| 137 update_li] + |
| 138 [['git', 'add'] + ['expectations/bench/%s' % i for i in update_li], |
| 139 ['git', 'commit', '-m', commit_msg], |
| 140 upload, |
| 141 ['git', 'checkout', 'master'], |
| 142 ['git', 'branch', '-D', exp_dir], |
| 143 ]) |
| 144 status = True |
| 145 for cmd in cmds: |
| 146 print 'Running ' + ' '.join(cmd) |
| 147 if subprocess.call(cmd): |
| 148 print 'FAILED. Please check if skia git repo is present.' |
| 149 subprocess.call(['git', 'checkout', 'master']) |
| 150 status = False |
| 151 break |
| 152 os.chdir(old_cwd) |
| 153 return status |
| 154 |
| 155 def delete_dirs(li): |
| 156 for d in li: |
| 157 print 'Deleting directory %s' % d |
| 158 shutil.rmtree(d) |
| 159 |
| 160 |
| 161 def main(): |
| 162 d = os.path.dirname(os.path.abspath(__file__)) |
| 163 os.chdir(d) |
| 164 if not subprocess.call(['git', 'rev-parse'], stderr=subprocess.PIPE): |
| 165 print 'Please copy script to a separate dir outside git repos to use.' |
| 166 return |
| 167 parser = argparse.ArgumentParser() |
| 168 parser.add_argument('--githash', |
| 169 help='Githash prefix (7+ chars) to rebaseline to.') |
| 170 parser.add_argument('--commit', action='store_true', |
| 171 help='Whether to commit changes automatically.') |
| 172 args = parser.parse_args() |
| 173 |
| 174 repo_dir = os.path.join(d, 'skia') |
| 175 if not os.path.exists(repo_dir): |
| 176 os.makedirs(repo_dir) |
| 177 if not checkout_or_update_skia(repo_dir): |
| 178 print 'ERROR setting up Skia repo at %s' % repo_dir |
| 179 return 1 |
| 180 |
| 181 for item in os.listdir(os.path.join(d, 'skia/expectations/bench')): |
| 182 PLATFORMS.append( |
| 183 item.replace('bench_expectations_', '').replace('.txt', '')) |
| 184 |
| 185 file_in_repo = os.path.join(d, 'skia/experimental/benchtools/rebase.py') |
| 186 if not filecmp.cmp(__file__, file_in_repo): |
| 187 shutil.copy(file_in_repo, __file__) |
| 188 print 'Updated this script from repo; please run again.' |
| 189 return |
| 190 |
| 191 if not args.githash or len(args.githash) < 7: |
| 192 raise Exception('Please provide --githash with a longer prefix (7+).') |
| 193 commit = False |
| 194 if args.commit: |
| 195 commit = True |
| 196 rebase_hash = args.githash[:7] |
| 197 hashes = get_git_hashes() |
| 198 short_hashes = [h[:7] for h in hashes] |
| 199 if rebase_hash not in short_hashes: |
| 200 raise Exception('Provided --githash not found in recent history!') |
| 201 hashes = hashes[:short_hashes.index(rebase_hash) + 1] |
| 202 update_li = [] |
| 203 |
| 204 ts_str = '%s' % time.time() |
| 205 gs_dir = os.path.join(d, 'gs' + ts_str) |
| 206 exp_dir = os.path.join(d, 'exp' + ts_str) |
| 207 clean_dir(gs_dir) |
| 208 clean_dir(exp_dir) |
| 209 for p in PLATFORMS: |
| 210 clean_dir(os.path.join(gs_dir, p)) |
| 211 hash_to_use = '' |
| 212 for h in reversed(hashes): |
| 213 li = get_gs_filelist(p, h) |
| 214 if len(li) != 4: # no or partial data |
| 215 continue |
| 216 if download_gs_files(p, h, gs_dir): |
| 217 print 'Copied %s/%s' % (p, h) |
| 218 hash_to_use = h |
| 219 break |
| 220 else: |
| 221 print 'DOWNLOAD BENCH FAILED %s/%s' % (p, h) |
| 222 break |
| 223 if hash_to_use: |
| 224 if calc_expectations(p, h, gs_dir, exp_dir, repo_dir): |
| 225 update_li.append('bench_expectations_%s.txt' % p) |
| 226 if not update_li: |
| 227 print 'No bench data to update after %s!' % args.githash |
| 228 elif not git_commit_expectations( |
| 229 repo_dir, exp_dir, update_li, args.githash[:7], commit): |
| 230 print 'ERROR uploading expectations using git.' |
| 231 elif not commit: |
| 232 print 'CL created. Please take a look at the link above.' |
| 233 else: |
| 234 print 'New bench baselines should be in CQ now.' |
| 235 delete_dirs([gs_dir, exp_dir]) |
| 236 |
| 237 |
| 238 if __name__ == "__main__": |
| 239 main() |
OLD | NEW |