| #! /usr/bin/env python |
| # Copyright 2018 Google LLC. |
| # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. |
| |
| import json |
| import md5 |
| import multiprocessing |
| import os |
| import shutil |
| import sys |
| import tempfile |
| import urllib |
| import urllib2 |
| |
| from subprocess import check_call, check_output |
| |
| assert '/' in [os.sep, os.altsep] and os.pardir == '..' |
| |
| ASSETS = 'platform_tools/android/apps/skqp/src/main/assets' |
| BUCKET = 'skia-skqp-assets' |
| |
| def make_skqp_model(arg): |
| name, urls, exe = arg |
| tmp = tempfile.mkdtemp() |
| for url in urls: |
| urllib.urlretrieve(url, tmp + '/' + url[url.rindex('/') + 1:]) |
| check_call([exe, tmp, ASSETS + '/gmkb/' + name]) |
| shutil.rmtree(tmp) |
| sys.stdout.write(name + ' ') |
| sys.stdout.flush() |
| |
| def goldgetter(meta, exe): |
| assert os.path.exists(exe) |
| jobs = [] |
| for rec in meta: |
| urls = [d['URL'] for d in rec['digests'] |
| if d['status'] == 'positive' and |
| (set(d['paramset']['config']) & set(['vk', 'gles']))] |
| if urls: |
| jobs.append((rec['testName'], urls, exe)) |
| pool = multiprocessing.Pool(processes=20) |
| pool.map(make_skqp_model, jobs) |
| sys.stdout.write('\n') |
| return set((n for n, _, _ in jobs)) |
| |
| def gold(first_commit, last_commit): |
| c1, c2 = (check_output(['git', 'rev-parse', c]).strip() |
| for c in (first_commit, last_commit)) |
| f = urllib2.urlopen('https://public-gold.skia.org/json/export?' + urllib.urlencode([ |
| ('fbegin', c1), |
| ('fend', c2), |
| ('query', 'config=gles&config=vk&source_type=gm'), |
| ('pos', 'true'), |
| ('neg', 'false'), |
| ('unt', 'false') |
| ])) |
| j = json.load(f) |
| f.close() |
| return j |
| |
| def gset(path): |
| s = set() |
| if os.path.isfile(path): |
| with open(path, 'r') as f: |
| for line in f: |
| s.add(line.strip()) |
| return s |
| |
| def make_rendertest_list(models, good, bad): |
| assert good.isdisjoint(bad) |
| do_score = good & models |
| no_score = bad | (good - models) |
| to_delete = models & bad |
| for d in to_delete: |
| path = ASSETS + '/gmkb/' + d |
| if os.path.isdir(path): |
| shutil.rmtree(path) |
| results = dict() |
| for n in do_score: |
| results[n] = 0 |
| for n in no_score: |
| results[n] = -1 |
| return ''.join('%s,%d\n' % (n, results[n]) for n in sorted(results)) |
| |
| def get_digest(path): |
| m = md5.new() |
| with open(path, 'r') as f: |
| m.update(f.read()) |
| return m.hexdigest() |
| |
| def upload_cmd(path, digest): |
| return ['gsutil', 'cp', path, 'gs://%s/%s' % (BUCKET, digest)] |
| |
| def upload_model(): |
| bucket_url = 'gs://%s/' % BUCKET |
| extant = set((u.replace(bucket_url, '', 1) |
| for u in check_output(['gsutil', 'ls', bucket_url]).splitlines() if u)) |
| cmds = [] |
| filelist = [] |
| for dirpath, _, filenames in os.walk(ASSETS + '/gmkb'): |
| for filename in filenames: |
| path = os.path.join(dirpath, filename) |
| digest = get_digest(path) |
| if digest not in extant: |
| cmds.append(upload_cmd(path, digest)) |
| filelist.append('%s;%s\n' % (digest, os.path.relpath(path, ASSETS))) |
| tmp = tempfile.mkdtemp() |
| filelist_path = tmp + '/x' |
| with open(filelist_path, 'w') as o: |
| for l in filelist: |
| o.write(l) |
| filelist_digest = get_digest(filelist_path) |
| if filelist_digest not in extant: |
| cmds.append(upload_cmd(filelist_path, filelist_digest)) |
| |
| pool = multiprocessing.Pool(processes=20) |
| pool.map(check_call, cmds) |
| shutil.rmtree(tmp) |
| return filelist_digest |
| |
| def remove(x): |
| if os.path.isdir(x) and not os.path.islink(x): |
| shutil.rmtree(x) |
| if os.path.exists(x): |
| os.remove(x) |
| |
| def main(first_commit, last_commit): |
| check_call(upload_cmd('/dev/null', get_digest('/dev/null'))) |
| |
| os.chdir(os.path.dirname(__file__) + '/../..') |
| remove(ASSETS + '/files.checksum') |
| for d in [ASSETS + '/gmkb', ASSETS + '/skqp', ]: |
| remove(d) |
| os.mkdir(d) |
| |
| check_call([sys.executable, 'tools/git-sync-deps'], |
| env=dict(os.environ, GIT_SYNC_DEPS_QUIET='T')) |
| build = 'out/ndebug' |
| check_call(['bin/gn', 'gen', build, |
| '--args=cc="clang" cxx="clang++" is_debug=false']) |
| check_call(['ninja', '-C', build, |
| 'jitter_gms', 'list_gpu_unit_tests', 'make_skqp_model']) |
| |
| models = goldgetter(gold(first_commit, last_commit), build + '/make_skqp_model') |
| |
| check_call([build + '/jitter_gms', 'tools/skqp/bad_gms.txt']) |
| |
| with open(ASSETS + '/skqp/rendertests.txt', 'w') as o: |
| o.write(make_rendertest_list(models, gset('good.txt'), gset('bad.txt'))) |
| |
| remove('good.txt') |
| remove('bad.txt') |
| |
| with open(ASSETS + '/skqp/unittests.txt', 'w') as o: |
| o.write(check_output([build + '/list_gpu_unit_tests'])) |
| |
| with open(ASSETS + '/files.checksum', 'w') as o: |
| o.write(upload_model() + '\n') |
| |
| sys.stdout.write(ASSETS + '/files.checksum\n') |
| sys.stdout.write(ASSETS + '/skqp/rendertests.txt\n') |
| sys.stdout.write(ASSETS + '/skqp/unittests.txt\n') |
| |
| if __name__ == '__main__': |
| if len(sys.argv) != 3: |
| sys.stderr.write('Usage:\n %s C1 C2\n\n' % sys.argv[0]) |
| sys.exit(1) |
| main(sys.argv[1], sys.argv[2]) |