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

Side by Side Diff: scripts/slave/results_dashboard.py

Issue 545803002: Update buildbots to parse new telemetry JSON format. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Switched to having telemetry output json to files. Created 6 years, 3 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
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Functions for adding results to perf dashboard.""" 6 """Functions for adding results to perf dashboard."""
7 7
8 import calendar 8 import calendar
9 import datetime 9 import datetime
10 import httplib 10 import httplib
11 import json 11 import json
12 import logging
ghost stip (do not use) 2014/09/09 02:20:06 left in from debugging?
12 import os 13 import os
13 import urllib 14 import urllib
14 import urllib2 15 import urllib2
15 16
16 from slave import slave_utils 17 from slave import slave_utils
17 18
18 # The paths in the results dashboard URLs for sending and viewing results. 19 # The paths in the results dashboard URLs for sending and viewing results.
19 SEND_RESULTS_PATH = '/add_point' 20 SEND_RESULTS_PATH = '/add_point'
20 RESULTS_LINK_PATH = '/report?masters=%s&bots=%s&tests=%s&rev=%s' 21 RESULTS_LINK_PATH = '/report?masters=%s&bots=%s&tests=%s&rev=%s'
21 22
22 # CACHE_DIR/CACHE_FILENAME will be created in options.build_dir to cache 23 # CACHE_DIR/CACHE_FILENAME will be created in options.build_dir to cache
23 # results which need to be retried. 24 # results which need to be retried.
24 CACHE_DIR = 'results_dashboard' 25 CACHE_DIR = 'results_dashboard'
25 CACHE_FILENAME = 'results_to_retry' 26 CACHE_FILENAME = 'results_to_retry'
26 27
27 28
29 def SendChartJsonResults(chart_json, ref_json, revision_data, bot, mastername,
30 buildername, buildnumber, supplemental_dict, url,
31 build_dir):
qyearsley 2014/09/09 20:22:54 What about having a function which just constructs
sullivan 2014/09/11 00:25:56 Done.
32 # The master name used for the dashboard is the CamelCase name returned by
33 # GetActiveMaster(), and not the canonical master name with dots.
34 if not chart_json:
35 print 'Error: No json output from telemetry.'
36 print '@@@STEP_EXCEPTION@@@'
37 master = slave_utils.GetActiveMaster()
38 point_id, default_rev, versions = _RevisionNumberColumns(
39 revision_data, master, '')
40 supplemental_columns = {'default_rev': default_rev}
41 for key in supplemental_dict:
42 supplemental_columns[key.replace('a_', '', 1)] = supplemental_dict[key]
43 fields = {
44 'master': master,
45 'bot': bot,
46 'masterid': mastername,
47 'buildername': buildername,
48 'buildnumber': buildnumber,
49 'point_id': point_id,
50 'supplemental': supplemental_columns,
51 'versions': versions,
52 'chart_data': chart_json,
53 'is_ref': False,
54 }
55 SendResults(fields, url, build_dir)
56 if ref_json:
ghost stip (do not use) 2014/09/09 02:20:06 so the file will always exist, but the telemeteriz
sullivan 2014/09/11 00:25:55 In telemetry_utils.TelemetryResultsTracker._GetFil
57 fields['is_ref'] = True
58 fields['chart_data'] = ref_json
59 SendResults(fields, url, build_dir)
60
61
28 def SendResults(data, url, build_dir): 62 def SendResults(data, url, build_dir):
29 """Sends results to the Chrome Performance Dashboard. 63 """Sends results to the Chrome Performance Dashboard.
30 64
31 This function tries to send the given data to the dashboard, in addition to 65 This function tries to send the given data to the dashboard, in addition to
32 any data from the cache file. The cache file contains any data that wasn't 66 any data from the cache file. The cache file contains any data that wasn't
33 successfully sent in a previous run. 67 successfully sent in a previous run.
34 68
35 Args: 69 Args:
36 data: The data to try to send. Must be JSON-serializable. 70 data: The data to try to send. Must be JSON-serializable.
37 url: Performance Dashboard URL (including schema). 71 url: Performance Dashboard URL (including schema).
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 Each dictionary has the keys "master", "bot", "test", "value", "revision". 205 Each dictionary has the keys "master", "bot", "test", "value", "revision".
172 The full details of this format are described at http://goo.gl/TcJliv. 206 The full details of this format are described at http://goo.gl/TcJliv.
173 """ 207 """
174 results = [] 208 results = []
175 209
176 # The master name used for the dashboard is the CamelCase name returned by 210 # The master name used for the dashboard is the CamelCase name returned by
177 # GetActiveMaster(), and not the canonical master name with dots. 211 # GetActiveMaster(), and not the canonical master name with dots.
178 master = slave_utils.GetActiveMaster() 212 master = slave_utils.GetActiveMaster()
179 213
180 for chart_name, chart_data in sorted(charts.items()): 214 for chart_name, chart_data in sorted(charts.items()):
181 revision, revision_columns = _RevisionNumberColumns(chart_data, master) 215 revision, default_rev, revision_columns = _RevisionNumberColumns(
216 chart_data, master)
ghost stip (do not use) 2014/09/09 02:24:16 this needs a prefix, right? 'r_' ?
eakuefner 2014/09/09 21:00:54 Actually, to clarify, the r_ and a_ prefixes are a
sullivan 2014/09/11 00:25:56 Yep.
182 217
183 for trace_name, trace_values in sorted(chart_data['traces'].items()): 218 for trace_name, trace_values in sorted(chart_data['traces'].items()):
184 is_important = trace_name in chart_data.get('important', []) 219 is_important = trace_name in chart_data.get('important', [])
185 test_path = _TestPath(test_name, chart_name, trace_name) 220 test_path = _TestPath(test_name, chart_name, trace_name)
186 result = { 221 result = {
187 'master': master, 222 'master': master,
188 'bot': bot, 223 'bot': bot,
189 'test': test_path, 224 'test': test_path,
190 'revision': revision, 225 'revision': revision,
191 'masterid': mastername, 226 'masterid': mastername,
192 'buildername': buildername, 227 'buildername': buildername,
193 'buildnumber': buildnumber, 228 'buildnumber': buildnumber,
194 'supplemental_columns': {} 229 'supplemental_columns': {'a_default_rev': default_rev}
195 } 230 }
196 231
197 # Add the supplemental_columns values that were passed in after the 232 # Add the supplemental_columns values that were passed in after the
198 # calculated revision column values so that these can be overwritten. 233 # calculated revision column values so that these can be overwritten.
199 result['supplemental_columns'].update(revision_columns) 234 result['supplemental_columns'].update(revision_columns)
200 result['supplemental_columns'].update(supplemental_columns) 235 result['supplemental_columns'].update(supplemental_columns)
201 236
202 # Check whether this result is itself a time series (e.g. Endure result). 237 # Check whether this result is itself a time series (e.g. Endure result).
203 # If so add the key "data", otherwise add "value" and "error". 238 # If so add the key "data", otherwise add "value" and "error".
204 have_multi_value_data = False 239 have_multi_value_data = False
(...skipping 14 matching lines...) Expand all
219 if chart_data.get('stack'): 254 if chart_data.get('stack'):
220 result['stack'] = chart_data['stack'] 255 result['stack'] = chart_data['stack']
221 if is_important: 256 if is_important:
222 result['important'] = True 257 result['important'] = True
223 258
224 results.append(result) 259 results.append(result)
225 260
226 return results 261 return results
227 262
228 263
229 def _RevisionNumberColumns(data, master): 264 def _RevisionNumberColumns(data, master, prefix):
230 """Get the revision number and revision-related columns from the given data. 265 """Get the revision number and revision-related columns from the given data.
231 266
232 Args: 267 Args:
233 data: A dict of information from one line of the log file. 268 data: A dict of information from one line of the log file.
234 master: The name of the buildbot master. 269 master: The name of the buildbot master.
270 prefix: Prefix for keys. 'r_' for old-style json, '' for telemetry json.
235 271
236 Returns: 272 Returns:
237 A pair with the revision number (which must be an int), and a dict of 273 A 3-tuple with the revision number (which must be an int), the default rev
238 version-related supplemental columns. 274 name, and a dict of version-related supplemental columns.
239 """ 275 """
240 def GetTimestamp(): 276 def GetTimestamp():
241 """Get the Unix timestamp for the current time.""" 277 """Get the Unix timestamp for the current time."""
242 return int(calendar.timegm(datetime.datetime.utcnow().utctimetuple())) 278 return int(calendar.timegm(datetime.datetime.utcnow().utctimetuple()))
243 279
244 revision_supplemental_columns = {} 280 revision_supplemental_columns = {}
281 default_rev = None
245 282
246 # The dashboard requires points' x-values to be integers, and points are 283 # The dashboard requires points' x-values to be integers, and points are
247 # ordered by this. If the revision can't be parsed as an int, assume that 284 # ordered by this. If the revision can't be parsed as an int, assume that
248 # it's a git hash and use timestamp as the x-value. 285 # it's a git hash and use timestamp as the x-value.
249 git_hash = None 286 git_hash = None
250 try: 287 try:
251 revision = int(data['rev']) 288 revision = int(data['rev'])
252 except ValueError: 289 except ValueError:
253 # The dashboard requires ordered integer revision numbers. If the revision 290 # The dashboard requires ordered integer revision numbers. If the revision
254 # is not an integer, assume it's a git hash and send a timestamp. 291 # is not an integer, assume it's a git hash and send a timestamp.
255 revision = GetTimestamp() 292 revision = GetTimestamp()
256 git_hash = data['rev'] 293 git_hash = data['rev']
257 294
258 # Add Chromium version if it was specified, and use timestamp as x-value. 295 # Add Chromium version if it was specified, and use timestamp as x-value.
259 if 'ver' in data and data['ver'] != 'undefined': 296 if 'ver' in data and data['ver'] != 'undefined':
260 revision_supplemental_columns['r_chrome_version'] = data['ver'] 297 revision_supplemental_columns[prefix + 'chrome_version'] = data['ver']
261 revision_supplemental_columns['a_default_rev'] = 'r_chrome_version' 298 default_rev = 'r_chrome_version'
262 revision = GetTimestamp() 299 revision = GetTimestamp()
263 300
264 # Blink builds can have the same chromium revision for two builds. So 301 # Blink builds can have the same chromium revision for two builds. So
265 # order them by timestamp to get them to show on the dashboard in the 302 # order them by timestamp to get them to show on the dashboard in the
266 # order they were built. 303 # order they were built.
267 if master in ['ChromiumWebkit', 'Oilpan']: 304 if master in ['ChromiumWebkit', 'Oilpan']:
268 if not git_hash: 305 if not git_hash:
269 revision_supplemental_columns['r_chromium_svn'] = revision 306 revision_supplemental_columns[prefix + 'chromium_svn'] = revision
270 revision = GetTimestamp() 307 revision = GetTimestamp()
271 308
272 # Regardless of what the master is, if the given "rev" can't be parsed as 309 # Regardless of what the master is, if the given "rev" can't be parsed as
273 # an int, we're assuming that it's a git hash. 310 # an int, we're assuming that it's a git hash.
274 if git_hash: 311 if git_hash:
275 revision_supplemental_columns['r_chromium'] = git_hash 312 revision_supplemental_columns[prefix + 'chromium'] = git_hash
276 313
277 # For Oilpan, send the webkit_rev as r_oilpan since we are getting 314 # For Oilpan, send the webkit_rev as r_oilpan since we are getting
278 # the oilpan branch revision instead of the Blink trunk revision 315 # the oilpan branch revision instead of the Blink trunk revision
279 # and set r_oilpan to be the dashboard default revision. 316 # and set r_oilpan to be the dashboard default revision.
280 if master == 'Oilpan': 317 if master == 'Oilpan':
281 revision_supplemental_columns['r_oilpan'] = data['webkit_rev'] 318 revision_supplemental_columns[prefix + 'oilpan'] = data['webkit_rev']
282 revision_supplemental_columns['a_default_rev'] = 'r_oilpan' 319 default_rev = 'r_oilpan'
283 else: 320 else:
284 # For other revision data, add it if it's present and not undefined: 321 # For other revision data, add it if it's present and not undefined:
285 for key in ['webkit_rev', 'webrtc_rev', 'v8_rev']: 322 for key in ['webkit_rev', 'webrtc_rev', 'v8_rev']:
286 if key in data and data[key] != 'undefined': 323 if key in data and data[key] != 'undefined':
287 revision_supplemental_columns['r_' + key] = data[key] 324 revision_supplemental_columns[prefix + key] = data[key]
288 325
289 # If possible, also send the git hash. 326 # If possible, also send the git hash.
290 # If no other "default revision" type is specified already, use the git hash. 327 # If no other "default revision" type is specified already, use the git hash.
291 # This will change how it is displayed on the perf dashboard. 328 # This will change how it is displayed on the perf dashboard.
292 if 'git_revision' in data and data['git_revision'] != 'undefined': 329 if 'git_revision' in data and data['git_revision'] != 'undefined':
293 revision_supplemental_columns['r_chromium'] = data['git_revision'] 330 revision_supplemental_columns[prefix + 'chromium'] = data['git_revision']
294 if 'a_default_rev' not in revision_supplemental_columns: 331 if not default_rev:
295 revision_supplemental_columns['a_default_rev'] = 'r_chromium' 332 default_rev = 'r_chromium'
296 333
297 return revision, revision_supplemental_columns 334 return revision, default_rev, revision_supplemental_columns
298 335
299 336
300 def _TestPath(test_name, chart_name, trace_name): 337 def _TestPath(test_name, chart_name, trace_name):
301 """Get the slash-separated test path to send. 338 """Get the slash-separated test path to send.
302 339
303 Args: 340 Args:
304 test: Test name. Typically, this will be a top-level 'test suite' name. 341 test: Test name. Typically, this will be a top-level 'test suite' name.
305 chart_name: Name of a chart where multiple trace lines are grouped. If the 342 chart_name: Name of a chart where multiple trace lines are grouped. If the
306 chart name is the same as the trace name, that signifies that this is 343 chart name is the same as the trace name, that signifies that this is
307 the main trace for the chart. 344 the main trace for the chart.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 def _LinkAnnotation(url, data): 397 def _LinkAnnotation(url, data):
361 """Prints a link annotation with a link to the dashboard if possible. 398 """Prints a link annotation with a link to the dashboard if possible.
362 399
363 Args: 400 Args:
364 url: The Performance Dashboard URL, e.g. "https://chromeperf.appspot.com" 401 url: The Performance Dashboard URL, e.g. "https://chromeperf.appspot.com"
365 data: The data that's being sent to the dashboard. 402 data: The data that's being sent to the dashboard.
366 403
367 Returns: 404 Returns:
368 An annotation to print, or None. 405 An annotation to print, or None.
369 """ 406 """
370 if not data or type(data) is not list: 407 if not data:
371 return None 408 return None
372 point = data[0] 409 if type(data) is list:
410 master, bot, test, revision = (
411 data[0]['master'], data[0]['bot'], data[0]['test'], data[0]['revision'])
412 else:
413 master, bot, test, revision = (
414 data['master'], data['bot'], data['chart_data']['benchmark_name'],
415 data['point_id'])
373 results_link = url + RESULTS_LINK_PATH % ( 416 results_link = url + RESULTS_LINK_PATH % (
374 urllib.quote(point['master']), 417 urllib.quote(master), urllib.quote(bot), urllib.quote(test.split('/')[0]),
375 urllib.quote(point['bot']), 418 revision)
376 urllib.quote(point['test'].split('/')[0]),
377 point['revision'])
378 return '@@@STEP_LINK@%s@%s@@@' % ('Results Dashboard', results_link) 419 return '@@@STEP_LINK@%s@%s@@@' % ('Results Dashboard', results_link)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698