#! /usr/bin/env python # Copyright 2019 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 os import re import subprocess import sys import threading import urllib import urllib2 assert '/' in [os.sep, os.altsep] skia_directory = os.path.abspath(os.path.dirname(__file__) + '/../..') def get_jobs(): path = skia_directory + '/infra/bots/jobs.json' reg = re.compile('Test-(?P[A-Za-z0-9_]+)-' '(?P[A-Za-z0-9_]+)-' '(?P[A-Za-z0-9_]+)-GPU-' '(?P[A-Za-z0-9_]+)-' '(?P[A-Za-z0-9_]+)-' '(?P[A-Za-z0-9_]+)-' 'All(-(?P[A-Za-z0-9_]+)|)') keys = ['os', 'compiler', 'model', 'cpu_or_gpu_value', 'arch', 'configuration', 'extra_config'] def fmt(s): return s.encode('utf-8') if s is not None else '' with open(path) as f: jobs = json.load(f) for job in jobs: m = reg.match(job) if m is not None: yield [(k, fmt(m.group(k))) for k in keys] def gold_export_url(job, config, first_commit, last_commit): qq = [('source_type', 'gm'), ('config', config)] + job query = [ ('fbegin', first_commit), ('fend', last_commit), ('query', urllib.urlencode(qq)), ('pos', 'true'), ('neg', 'false'), ('unt', 'false'), ('head', 'true') ] return 'https://public-gold.skia.org/json/export?' + urllib.urlencode(query) def urlopen(url): cookie = os.environ.get('SKIA_GOLD_COOKIE', '') return urllib2.urlopen(urllib2.Request(url, headers={'Cookie': cookie})) def get_results_for_commit(commit, jobs): sys.stderr.write('%s\n' % commit) sys.stderr.flush() CONFIGS = ['gles', 'vk'] passing_tests_for_all_jobs = [] def process(url): try: testResults = json.load(urlopen(url)) except urllib2.URLError: sys.stderr.write('\nerror "%s":\n' % url) return sys.stderr.write('.') sys.stderr.flush() passing_tests = 0 for t in testResults: assert t['digests'] passing_tests += 1 passing_tests_for_all_jobs.append(passing_tests) all_urls = [gold_export_url(job, config, commit, commit) for job in jobs for config in CONFIGS] threads = [threading.Thread(target=process, args=(url,)) for url in all_urls] for t in threads: t.start() for t in threads: t.join() result = sum(passing_tests_for_all_jobs) sys.stderr.write('\n%d\n' % result) sys.stderr.flush() return result def find_best_commit(commits): jobs = [j for j in get_jobs()] results = [] for commit_name in commits: commit_hash = subprocess.check_output(['git', 'rev-parse', commit_name]).strip() results.append((commit_hash, get_results_for_commit(commit_hash, jobs))) best_result = max(r for h, r in results) for h, r in results: if r == best_result: return h return None def generate_commit_list(args): return subprocess.check_output(['git', 'log', '--format=%H'] + args).splitlines() def main(args): os.chdir(skia_directory) subprocess.check_call(['git', 'fetch', 'origin']) sys.stderr.write('%s\n' % ' '.join(args)) commits = generate_commit_list(args) sys.stderr.write('%d\n' % len(commits)) best = find_best_commit(commits) sys.stderr.write('DONE:\n') sys.stderr.flush() sys.stdout.write('%s\n' % best) usage = '''Example usage: python %s origin/master ^origin/skqp/dev < /dev/null > LOG 2>&1 & disown ''' if __name__ == '__main__': if len(sys.argv) < 2: sys.stderr.write(usage % sys.argv[0]) sys.exit(1) main(sys.argv[1:])