Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(791)

Side by Side Diff: content/test/gpu/gather_swarming_json_results.py

Issue 2116593004: Add script which gathers JSON output from a Swarming task's shards. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased and re-scraped test times. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Script which gathers and merges the JSON results from multiple
7 swarming shards of a step on the waterfall.
8
9 This is used to feed in the per-test times of previous runs of tests
10 to the browser_test_runner's sharding algorithm, to improve shard
11 distribution.
12 """
13
14 import argparse
15 import json
16 import os
17 import shutil
18 import subprocess
19 import sys
20 import tempfile
21 import urllib
22 import urllib2
23
24 SWARMING_SERVICE = 'https://chromium-swarm.appspot.com'
25
26 THIS_DIR = os.path.dirname(os.path.abspath(__file__))
27 SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(THIS_DIR)))
28 SWARMING_CLIENT_DIR = os.path.join(SRC_DIR, 'tools', 'swarming_client')
29
30 class Swarming:
31 @staticmethod
32 def CheckAuth():
33 output = subprocess.check_output([
34 os.path.join(SWARMING_CLIENT_DIR, 'auth.py'),
35 'check',
36 '--service',
37 SWARMING_SERVICE])
38 if not output.startswith('user:'):
39 print 'Must run:'
40 print ' tools/swarming_client/auth.py login --service ' + \
41 SWARMING_SERVICE
42 print 'and authenticate with @google.com credentials.'
43 sys.exit(1)
44
45 @staticmethod
46 def Collect(taskIDs, output_dir, verbose):
47 cmd = [
48 os.path.join(SWARMING_CLIENT_DIR, 'swarming.py'),
49 'collect',
50 '-S',
51 SWARMING_SERVICE,
52 '--task-output-dir',
53 output_dir] + taskIDs
54 if verbose:
55 print 'Collecting Swarming results:'
56 print cmd
57 if verbose > 1:
58 # Print stdout from the collect command.
59 stdout = None
60 else:
61 fnull = open(os.devnull, 'w')
62 stdout = fnull
63 subprocess.check_call(cmd, stdout=stdout, stderr=subprocess.STDOUT)
64
65 @staticmethod
66 def ExtractShardTaskIDs(urls):
67 SWARMING_URL = 'https://chromium-swarm.appspot.com/user/task/'
68 taskIDs = []
69 for k,v in urls.iteritems():
70 if not k.startswith('shard'):
71 raise Exception('Illegally formatted \'urls\' key %s' % k)
72 if not v.startswith(SWARMING_URL):
73 raise Exception('Illegally formatted \'urls\' value %s' % v)
74 taskIDs.append(v[len(SWARMING_URL):])
75 return taskIDs
76
77 class Waterfall:
78 def __init__(self, waterfall):
79 self._waterfall = waterfall
80 self.BASE_URL = 'http://build.chromium.org/p/'
81 self.BASE_JSON_BUILDERS_URL = self.BASE_URL + '%s/json/builders'
82 self.BASE_JSON_BUILDS_URL = self.BASE_JSON_BUILDERS_URL + '/%s/builds'
83
84 def GetJsonFromUrl(self, url):
85 conn = urllib2.urlopen(url)
86 result = conn.read()
87 conn.close()
88 return json.loads(result)
89
90 def GetBuildNumbersForBot(self, bot):
91 builds_json = self.GetJsonFromUrl(
92 self.BASE_JSON_BUILDS_URL %
93 (self._waterfall, urllib.quote(bot)))
94 build_numbers = [int(k) for k in builds_json.keys()]
95 build_numbers.sort()
96 return build_numbers
97
98 def GetMostRecentlyCompletedBuildNumberForBot(self, bot):
99 builds = self.GetBuildNumbersForBot(bot)
100 return builds[len(builds) - 1]
101
102 def GetJsonForBuild(self, bot, build):
103 return self.GetJsonFromUrl(
104 (self.BASE_JSON_BUILDS_URL + '/%d') %
105 (self._waterfall, urllib.quote(bot), build))
106
107
108 def JsonLoadStrippingUnicode(file, **kwargs):
109 def StripUnicode(obj):
110 if isinstance(obj, unicode):
111 try:
112 return obj.encode('ascii')
113 except UnicodeEncodeError:
114 return obj
115
116 if isinstance(obj, list):
117 return map(StripUnicode, obj)
118
119 if isinstance(obj, dict):
120 new_obj = type(obj)(
121 (StripUnicode(k), StripUnicode(v)) for k, v in obj.iteritems() )
122 return new_obj
123
124 return obj
125
126 return StripUnicode(json.load(file, **kwargs))
127
128
129 def Merge(dest, src):
130 if isinstance(dest, list):
131 if not isinstance(src, list):
132 raise Exception('Both must be lists: ' + dest + ' and ' + src)
133 return dest + src
134
135 if isinstance(dest, dict):
136 if not isinstance(src, dict):
137 raise Exception('Both must be dicts: ' + dest + ' and ' + src)
138 for k in src.iterkeys():
139 if k not in dest:
140 dest[k] = src[k]
141 else:
142 dest[k] = Merge(dest[k], src[k])
143 return dest
144
145 return src
146
147
148 def main():
149 rest_args = sys.argv[1:]
150 parser = argparse.ArgumentParser(
151 description='Gather JSON results from a run of a Swarming test.',
152 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
153 parser.add_argument('-v', '--verbose', action='count', default=0,
154 help='Enable verbose output (specify multiple times '
155 'for more output)')
156 parser.add_argument('--waterfall', type=str, default='chromium.gpu.fyi',
157 help='Which waterfall to examine')
158 parser.add_argument('--bot', type=str, default='Linux Release (NVIDIA)',
159 help='Which bot on the waterfall to examine')
160 parser.add_argument('--build', default=-1, type=int,
161 help='Which build to fetch (-1 means most recent)')
162 parser.add_argument('--step', type=str, default='webgl2_conformance_tests',
163 help='Which step to fetch (treated as a prefix)')
164 parser.add_argument('--output', type=str, default='output.json',
165 help='Name of output file')
166 parser.add_argument('--leak-temp-dir', action='store_true', default=False,
167 help='Deliberately leak temporary directory')
168
169 options = parser.parse_args(rest_args)
170
171 Swarming.CheckAuth()
172
173 waterfall = Waterfall(options.waterfall)
174 build = options.build
175 if build < 0:
176 build = waterfall.GetMostRecentlyCompletedBuildNumberForBot(options.bot)
177
178 build_json = waterfall.GetJsonForBuild(options.bot, build)
179
180 if options.verbose:
181 print 'Fetching information from %s, bot %s, build %s' % (
182 options.waterfall, options.bot, build)
183
184 taskIDs = []
185 for s in build_json['steps']:
186 if s['name'].startswith(options.step):
187 # Found the step.
188 #
189 # The Swarming shards happen to be listed in the 'urls' property
190 # of the step. Iterate down them.
191 if 'urls' not in s or not s['urls']:
192 # Note: we could also just download json.output if it exists.
193 print ('%s on waterfall %s, bot %s, build %s doesn\'t '
194 'look like a Swarmed task') % (
195 s['name'], options.waterfall, options.bot, build)
196 return 1
197 taskIDs = Swarming.ExtractShardTaskIDs(s['urls'])
198 if options.verbose:
199 print 'Found Swarming task IDs for step %s' % s['name']
200
201 break
202 if not taskIDs:
203 print 'Problem gathering the Swarming task IDs for %s' % options.step
204 return 1
205
206 # Collect the results.
207 tmpdir = tempfile.mkdtemp()
208 Swarming.Collect(taskIDs, tmpdir, options.verbose)
209
210 # Shards' JSON outputs are in sequentially-numbered subdirectories
211 # of the output directory.
212 merged_json = None
213 for i in xrange(len(taskIDs)):
214 with open(os.path.join(tmpdir, str(i), 'output.json')) as f:
215 cur_json = JsonLoadStrippingUnicode(f)
216 if not merged_json:
217 merged_json = cur_json
218 else:
219 merged_json = Merge(merged_json, cur_json)
220
221 with open(options.output, 'w') as f:
222 json.dump(merged_json, f, sort_keys=True, indent=2,
223 separators=(',', ': '))
224
225 if options.leak_temp_dir:
226 print 'Temporary directory: %s' % tmpdir
227 else:
228 shutil.rmtree(tmpdir)
229
230 return 0
231
232
233 if __name__ == "__main__":
234 sys.exit(main())
OLDNEW
« no previous file with comments | « content/test/data/gpu/webgl2_conformance_tests_output.json ('k') | content/test/gpu/generate_buildbot_json.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698