• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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