1#! /usr/bin/env python 2# Copyright 2018 Google LLC. 3# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 4 5import json 6import md5 7import multiprocessing 8import os 9import shutil 10import sys 11import tempfile 12import urllib 13import urllib2 14 15from subprocess import check_call, check_output 16 17assert '/' in [os.sep, os.altsep] and os.pardir == '..' 18 19ASSETS = 'platform_tools/android/apps/skqp/src/main/assets' 20BUCKET = 'skia-skqp-assets' 21 22def make_skqp_model(arg): 23 name, urls, exe = arg 24 tmp = tempfile.mkdtemp() 25 for url in urls: 26 urllib.urlretrieve(url, tmp + '/' + url[url.rindex('/') + 1:]) 27 check_call([exe, tmp, ASSETS + '/gmkb/' + name]) 28 shutil.rmtree(tmp) 29 sys.stdout.write(name + ' ') 30 sys.stdout.flush() 31 32def goldgetter(meta, exe): 33 assert os.path.exists(exe) 34 jobs = [] 35 for rec in meta: 36 urls = [d['URL'] for d in rec['digests'] 37 if d['status'] == 'positive' and 38 (set(d['paramset']['config']) & set(['vk', 'gles']))] 39 if urls: 40 jobs.append((rec['testName'], urls, exe)) 41 pool = multiprocessing.Pool(processes=20) 42 pool.map(make_skqp_model, jobs) 43 sys.stdout.write('\n') 44 return set((n for n, _, _ in jobs)) 45 46def gold(first_commit, last_commit): 47 c1, c2 = (check_output(['git', 'rev-parse', c]).strip() 48 for c in (first_commit, last_commit)) 49 f = urllib2.urlopen('https://public-gold.skia.org/json/export?' + urllib.urlencode([ 50 ('fbegin', c1), 51 ('fend', c2), 52 ('query', 'config=gles&config=vk&source_type=gm'), 53 ('pos', 'true'), 54 ('neg', 'false'), 55 ('unt', 'false') 56 ])) 57 j = json.load(f) 58 f.close() 59 return j 60 61def gset(path): 62 s = set() 63 if os.path.isfile(path): 64 with open(path, 'r') as f: 65 for line in f: 66 s.add(line.strip()) 67 return s 68 69def make_rendertest_list(models, good, bad): 70 assert good.isdisjoint(bad) 71 do_score = good & models 72 no_score = bad | (good - models) 73 to_delete = models & bad 74 for d in to_delete: 75 path = ASSETS + '/gmkb/' + d 76 if os.path.isdir(path): 77 shutil.rmtree(path) 78 results = dict() 79 for n in do_score: 80 results[n] = 0 81 for n in no_score: 82 results[n] = -1 83 return ''.join('%s,%d\n' % (n, results[n]) for n in sorted(results)) 84 85def get_digest(path): 86 m = md5.new() 87 with open(path, 'r') as f: 88 m.update(f.read()) 89 return m.hexdigest() 90 91def upload_cmd(path, digest): 92 return ['gsutil', 'cp', path, 'gs://%s/%s' % (BUCKET, digest)] 93 94def upload_model(): 95 bucket_url = 'gs://%s/' % BUCKET 96 extant = set((u.replace(bucket_url, '', 1) 97 for u in check_output(['gsutil', 'ls', bucket_url]).splitlines() if u)) 98 cmds = [] 99 filelist = [] 100 for dirpath, _, filenames in os.walk(ASSETS + '/gmkb'): 101 for filename in filenames: 102 path = os.path.join(dirpath, filename) 103 digest = get_digest(path) 104 if digest not in extant: 105 cmds.append(upload_cmd(path, digest)) 106 filelist.append('%s;%s\n' % (digest, os.path.relpath(path, ASSETS))) 107 tmp = tempfile.mkdtemp() 108 filelist_path = tmp + '/x' 109 with open(filelist_path, 'w') as o: 110 for l in filelist: 111 o.write(l) 112 filelist_digest = get_digest(filelist_path) 113 if filelist_digest not in extant: 114 cmds.append(upload_cmd(filelist_path, filelist_digest)) 115 116 pool = multiprocessing.Pool(processes=20) 117 pool.map(check_call, cmds) 118 shutil.rmtree(tmp) 119 return filelist_digest 120 121def remove(x): 122 if os.path.isdir(x) and not os.path.islink(x): 123 shutil.rmtree(x) 124 if os.path.exists(x): 125 os.remove(x) 126 127def main(first_commit, last_commit): 128 check_call(upload_cmd('/dev/null', get_digest('/dev/null'))) 129 130 os.chdir(os.path.dirname(__file__) + '/../..') 131 remove(ASSETS + '/files.checksum') 132 for d in [ASSETS + '/gmkb', ASSETS + '/skqp', ]: 133 remove(d) 134 os.mkdir(d) 135 136 check_call([sys.executable, 'tools/git-sync-deps'], 137 env=dict(os.environ, GIT_SYNC_DEPS_QUIET='T')) 138 build = 'out/ndebug' 139 check_call(['bin/gn', 'gen', build, 140 '--args=cc="clang" cxx="clang++" is_debug=false']) 141 check_call(['ninja', '-C', build, 142 'jitter_gms', 'list_gpu_unit_tests', 'make_skqp_model']) 143 144 models = goldgetter(gold(first_commit, last_commit), build + '/make_skqp_model') 145 146 check_call([build + '/jitter_gms', 'tools/skqp/bad_gms.txt']) 147 148 with open(ASSETS + '/skqp/rendertests.txt', 'w') as o: 149 o.write(make_rendertest_list(models, gset('good.txt'), gset('bad.txt'))) 150 151 remove('good.txt') 152 remove('bad.txt') 153 154 with open(ASSETS + '/skqp/unittests.txt', 'w') as o: 155 o.write(check_output([build + '/list_gpu_unit_tests'])) 156 157 with open(ASSETS + '/files.checksum', 'w') as o: 158 o.write(upload_model() + '\n') 159 160 sys.stdout.write(ASSETS + '/files.checksum\n') 161 sys.stdout.write(ASSETS + '/skqp/rendertests.txt\n') 162 sys.stdout.write(ASSETS + '/skqp/unittests.txt\n') 163 164if __name__ == '__main__': 165 if len(sys.argv) != 3: 166 sys.stderr.write('Usage:\n %s C1 C2\n\n' % sys.argv[0]) 167 sys.exit(1) 168 main(sys.argv[1], sys.argv[2]) 169