• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#! /usr/bin/env python
2# Copyright 2019 Google LLC.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import json
7import os
8import re
9import subprocess
10import sys
11import threading
12import urllib
13import urllib2
14
15
16assert '/' in [os.sep, os.altsep]
17
18
19skia_directory = os.path.abspath(os.path.dirname(__file__) + '/../..')
20
21
22def get_jobs():
23    path = skia_directory + '/infra/bots/jobs.json'
24    reg = re.compile('Test-(?P<os>[A-Za-z0-9_]+)-'
25                     '(?P<compiler>[A-Za-z0-9_]+)-'
26                     '(?P<model>[A-Za-z0-9_]+)-GPU-'
27                     '(?P<cpu_or_gpu_value>[A-Za-z0-9_]+)-'
28                     '(?P<arch>[A-Za-z0-9_]+)-'
29                     '(?P<configuration>[A-Za-z0-9_]+)-'
30                     'All(-(?P<extra_config>[A-Za-z0-9_]+)|)')
31    keys = ['os', 'compiler', 'model', 'cpu_or_gpu_value', 'arch',
32            'configuration', 'extra_config']
33    def fmt(s):
34        return s.encode('utf-8') if s is not None else ''
35    with open(path) as f:
36        jobs = json.load(f)
37    for job in jobs:
38        m = reg.match(job)
39        if m is not None:
40            yield [(k, fmt(m.group(k))) for k in keys]
41
42
43def gold_export_url(job, config, first_commit, last_commit):
44    qq = [('source_type', 'gm'), ('config', config)] + job
45    query = [
46        ('fbegin', first_commit),
47        ('fend', last_commit),
48        ('query', urllib.urlencode(qq)),
49        ('pos', 'true'),
50        ('neg', 'false'),
51        ('unt', 'false'),
52        ('head', 'true')
53    ]
54    return 'https://public-gold.skia.org/json/export?' + urllib.urlencode(query)
55
56
57def get_results_for_commit(commit, jobs):
58    sys.stderr.write('%s\n' % commit)
59    sys.stderr.flush()
60    CONFIGS = ['gles', 'vk']
61    passing_tests_for_all_jobs = []
62    def process(url):
63        testResults = json.load(urllib2.urlopen(url))
64        sys.stderr.write('.')
65        sys.stderr.flush()
66        passing_tests = 0
67        for t in testResults:
68            assert t['digests']
69            passing_tests += 1
70        passing_tests_for_all_jobs.append(passing_tests)
71    all_urls = [gold_export_url(job, config, commit, commit)
72                for job in jobs for config in CONFIGS]
73    threads = [threading.Thread(target=process, args=(url,)) for url in all_urls]
74    for t in threads:
75        t.start()
76    for t in threads:
77        t.join()
78    result = sum(passing_tests_for_all_jobs)
79    sys.stderr.write('\n%d\n' % result)
80    sys.stderr.flush()
81    return result
82
83
84def find_best_commit(commits):
85    jobs = [j for j in get_jobs()]
86    results = []
87    for commit_name in commits:
88        commit_hash = subprocess.check_output(['git', 'rev-parse', commit_name]).strip()
89        results.append((commit_hash, get_results_for_commit(commit_hash, jobs)))
90
91    best_result = max(r for h, r in results)
92    for h, r in results:
93        if r == best_result:
94            return h
95    return None
96
97
98def generate_commit_list(args):
99    return subprocess.check_output(['git', 'log', '--format=%H'] + args).splitlines()
100
101
102def main(args):
103    os.chdir(skia_directory)
104    subprocess.check_call(['git', 'fetch', 'origin'])
105    sys.stderr.write('%s\n' % ' '.join(args))
106    commits = generate_commit_list(args)
107    sys.stderr.write('%d\n' % len(commits))
108    best = find_best_commit(commits)
109    sys.stderr.write('DONE:\n')
110    sys.stderr.flush()
111    sys.stdout.write('%s\n' % best)
112
113
114usage = '''Example usage:
115    python %s origin/master ^origin/skqp/dev < /dev/null > LOG 2>&1 & disown
116'''
117
118if __name__ == '__main__':
119    if len(sys.argv) < 2:
120        sys.stderr.write(usage % sys.argv[0])
121        sys.exit(1)
122    main(sys.argv[1:])
123