Index: scripts/slave/results_dashboard.py |
diff --git a/scripts/slave/results_dashboard.py b/scripts/slave/results_dashboard.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9d0f06fa50678ca9576b39470b0bff4dc6ddfcd2 |
--- /dev/null |
+++ b/scripts/slave/results_dashboard.py |
@@ -0,0 +1,128 @@ |
+#!/usr/bin/env python |
+# Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Functions for adding results to perf dashboard.""" |
+ |
+import httplib |
+import json |
+import os |
+import urllib |
+import urllib2 |
+ |
+from slave import slave_utils |
+ |
+# The paths in the results dashboard URLs for sending and viewing results. |
+SEND_RESULTS_PATH = "/add_point" |
+RESULTS_LINK_PATH = "/report?masters=%s&bots=%s&tests=%s&rev=%s" |
+# CACHE_DIR/CACHE_FILENAME will be created in options.build_dir to cache |
+# results which need to be retried. |
+CACHE_DIR = "results_dashboard" |
+CACHE_FILENAME = "results_to_retry" |
+ |
+ |
+def SendResults(logname, lines, system, test, url, build_dir): |
+ if not logname.endswith("-summary.dat"): |
+ return |
+ |
+ new_results_line = _GetResultsJson(logname, lines, system, test, url) |
+ # Write the new request line to the cache, in case of errors. |
+ cache_filename = _GetCacheFileName(build_dir) |
+ cache = open(cache_filename, "ab") |
+ cache.write("\n" + new_results_line) |
+ cache.close() |
+ |
+ # Send all the results from this run and the previous cache to the dashboard. |
+ cache = open(cache_filename, "rb") |
+ cache_lines = cache.readlines() |
+ cache.close() |
+ errors = [] |
+ lines_to_retry = [] |
+ fatal_error = False |
+ for index, line in enumerate(cache_lines): |
+ line = line.strip() |
+ if not line: |
+ continue |
+ error = _SendResultsJson(url, line) |
+ if error: |
+ if index != len(cache_lines) -1: |
+ # This request has already been tried before, now it's fatal. |
+ fatal_error = True |
+ lines_to_retry.append(line) |
+ errors.append(error) |
+ |
+ # Write any failing requests to the cache. |
+ cache = open(cache_filename, "wb") |
+ cache.write("\n".join(set(lines_to_retry))) |
+ cache.close() |
+ |
+ # Print any errors, and if there was a fatal error, it should be an exception. |
+ for error in errors: |
+ print error |
+ if fatal_error: |
+ print "Multiple failures uploading to dashboard." |
+ print "@@@STEP_EXCEPTION@@@" |
+ |
+def _GetCacheFileName(build_dir): |
+ """Gets the cache filename, creating the file if it does not exist.""" |
+ cache_dir = os.path.join(os.path.abspath(build_dir), CACHE_DIR) |
+ if not os.path.exists(cache_dir): |
+ os.makedirs(cache_dir) |
+ cache_filename = os.path.join(cache_dir, CACHE_FILENAME) |
+ if not os.path.exists(cache_filename): |
+ # Create the file. |
+ open(cache_filename, "wb").close() |
+ return cache_filename |
+ |
+def _GetResultsJson(logname, lines, system, test, url): |
+ results_to_add = [] |
+ master = slave_utils.GetActiveMaster() |
+ bot = system |
+ graph = logname.replace("-summary.dat", "") |
+ for line in lines: |
+ data = json.loads(line) |
+ revision = data["rev"] |
+ for (trace, values) in data["traces"].iteritems(): |
+ if trace == graph + "_ref": |
+ trace = "ref" |
+ graph = graph.replace("_by_url", "") |
+ trace = trace.replace("/", "_") |
+ test_path = "%s/%s/%s" % (test, graph, trace) |
+ if graph == trace: |
+ test_path = "%s/%s" % (test, graph) |
+ result = { |
+ "master": master, |
+ "bot": system, |
+ "test": test_path, |
+ "revision": revision, |
+ "value": values[0], |
+ "error": values[1], |
+ } |
+ if "webkit_rev" in data and data["webkit_rev"] != "undefined": |
+ result.setdefault( |
+ "supplemental_columns", {})["r_webkit_rev"] = data["webkit_rev"] |
+ results_to_add.append(result) |
+ _PrintLinkStep(url, master, bot, test_path, revision) |
+ return json.dumps(results_to_add) |
+ |
+def _SendResultsJson(url, results_json): |
+ data = urllib.urlencode({"data": results_json}) |
+ req = urllib2.Request(url + SEND_RESULTS_PATH, data) |
+ try: |
+ urllib2.urlopen(req) |
+ except urllib2.HTTPError, e: |
+ return "HTTPError: %d for JSON %s\n" % (e.code, results_json) |
+ except urllib2.URLError, e: |
+ return "URLError: %s for JSON %s\n" % (str(e.reason), results_json) |
+ except httplib.HTTPException, e: |
+ return "HTTPException for JSON %s\n" % results_json |
+ return None |
+ |
+def _PrintLinkStep(url, master, bot, test_path, revision): |
+ results_link = url + RESULTS_LINK_PATH % ( |
+ urllib.quote(master), |
+ urllib.quote(bot), |
+ urllib.quote(test_path), |
+ revision) |
+ print "@@@STEP_LINK@%s@%s@@@" % ("Results Dashboard", results_link) |