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

Unified Diff: webkit/tools/layout_tests/layout_package/json_results_generator.py

Issue 201073: Run-length encode the JSON results. This makes them considerably... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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 side-by-side diff with in-line comments
Download patch
Index: webkit/tools/layout_tests/layout_package/json_results_generator.py
===================================================================
--- webkit/tools/layout_tests/layout_package/json_results_generator.py (revision 25738)
+++ webkit/tools/layout_tests/layout_package/json_results_generator.py (working copy)
@@ -15,7 +15,7 @@
class JSONResultsGenerator:
- MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG = 200
+ MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG = 500
# Min time (seconds) that will be added to the JSON.
MIN_TIME = 1
JSON_PREFIX = "ADD_RESULTS("
@@ -24,6 +24,12 @@
LAYOUT_TESTS_PATH = "layout_tests"
PASS_RESULT = "P"
NO_DATA_RESULT = "N"
+ VERSION = 1
+ VERSION_KEY = "version"
+ RESULTS = "results"
+ TIMES = "times"
+ BUILD_NUMBERS = "buildNumbers"
+ TESTS = "tests"
def __init__(self, failures, individual_test_timings, builder_name,
build_number, results_file_path, all_tests):
@@ -119,17 +125,19 @@
# just grab it from wherever it's archived to.
results_json = {}
+ self._ConvertJSONToCurrentVersion(results_json)
+
if self._builder_name not in results_json:
results_json[self._builder_name] = self._CreateResultsForBuilderJSON()
- tests = results_json[self._builder_name]["tests"]
+ tests = results_json[self._builder_name][self.TESTS]
all_failing_tests = set(self._failures.iterkeys())
all_failing_tests.update(tests.iterkeys())
- build_numbers = results_json[self._builder_name]["buildNumbers"]
+ build_numbers = results_json[self._builder_name][self.BUILD_NUMBERS]
build_numbers.insert(0, self._build_number)
build_numbers = build_numbers[:self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG]
- results_json[self._builder_name]["buildNumbers"] = build_numbers
+ results_json[self._builder_name][self.BUILD_NUMBERS] = build_numbers
num_build_numbers = len(build_numbers)
for test in all_failing_tests:
@@ -142,25 +150,66 @@
tests[test] = self._CreateResultsAndTimesJSON()
thisTest = tests[test]
- thisTest["results"] = result_and_time.result + thisTest["results"]
- thisTest["times"].insert(0, result_and_time.time)
-
+ self._InsertItemRunLengthEncoded(result_and_time.result,
+ thisTest[self.RESULTS])
+ self._InsertItemRunLengthEncoded(result_and_time.time,
+ thisTest[self.TIMES])
self._NormalizeResultsJSON(thisTest, test, tests, num_build_numbers)
# Specify separators in order to get compact encoding.
results_str = simplejson.dumps(results_json, separators=(',', ':'))
return self.JSON_PREFIX + results_str + self.JSON_SUFFIX
+ def _InsertItemRunLengthEncoded(self, item, encoded_results):
+ """Inserts the item into the run-length encoded results.
+
+ Args:
+ item: String or number to insert.
+ encoded_results: run-length encoded results. An array of arrays, e.g.
+ [[3,'A'],[1,'Q']] encodes AAAQ.
+ """
+ if len(encoded_results) and item == encoded_results[0][1]:
+ encoded_results[0][0] += 1
+ else:
+ # Use a list instead of a class for the run-length encoding since we
+ # want the serialized form to be concise.
+ encoded_results.insert(0, [1, item])
+
+ def _ConvertJSONToCurrentVersion(self, results_json):
+ """If the JSON does not match the current version, converts it to the
+ current version and adds in the new version number.
+ """
+ if (self.VERSION_KEY in results_json and
+ results_json[self.VERSION_KEY] == self.VERSION):
+ return
+
+ for builder in results_json:
+ tests = results_json[builder][self.TESTS]
+ for path in tests:
+ test = tests[path]
+ test[self.RESULTS] = self._RunLengthEncode(test[self.RESULTS])
+ test[self.TIMES] = self._RunLengthEncode(test[self.TIMES])
+
+ results_json[self.VERSION_KEY] = self.VERSION
+
+ def _RunLengthEncode(self, result_list):
+ """Run-length encodes a list or string of results."""
+ encoded_results = [];
+ current_result = None;
+ for item in reversed(result_list):
+ self._InsertItemRunLengthEncoded(item, encoded_results)
+ return encoded_results
+
def _CreateResultsAndTimesJSON(self):
results_and_times = {}
- results_and_times["results"] = ""
- results_and_times["times"] = []
+ results_and_times[self.RESULTS] = []
+ results_and_times[self.TIMES] = []
return results_and_times
def _CreateResultsForBuilderJSON(self):
results_for_builder = {}
- results_for_builder['buildNumbers'] = []
- results_for_builder['tests'] = {}
+ results_for_builder[self.BUILD_NUMBERS] = []
+ results_for_builder[self.TESTS] = {}
return results_for_builder
def _GetResultsCharForFailure(self, test):
@@ -182,6 +231,23 @@
else:
return "O"
+ def _RemoveItemsOverMaxNumberOfBuilds(self, encoded_list):
+ """Removes items from the run-length encoded list after the final itme that
+ exceeds the max number of builds to track.
+
+ Args:
+ encoded_results: run-length encoded results. An array of arrays, e.g.
+ [[3,'A'],[1,'Q']] encodes AAAQ.
+ """
+ num_builds = 0
+ index = 0
+ for result in encoded_list:
+ num_builds = num_builds + result[0]
+ index = index + 1
+ if num_builds > self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG:
+ return encoded_list[:index]
+ return encoded_list
+
def _NormalizeResultsJSON(self, test, test_path, tests, num_build_numbers):
""" Prune tests where all runs pass or tests that no longer exist and
truncate all results to maxNumberOfBuilds and pad results that don't
@@ -193,32 +259,15 @@
tests: The JSON object with all the test results for this builder.
num_build_numbers: The number to truncate/pad results to.
"""
- results = test["results"]
- num_results = len(results)
- times = test["times"]
+ test[self.RESULTS] = self._RemoveItemsOverMaxNumberOfBuilds(
+ test[self.RESULTS])
+ test[self.TIMES] = self._RemoveItemsOverMaxNumberOfBuilds(test[self.TIMES])
- if num_results != len(times):
- logging.error("Test has different number of build times versus results")
- times = []
- results = ""
- num_results = 0
-
- # Truncate or right-pad so there are exactly maxNumberOfBuilds results.
- if num_results > num_build_numbers:
- results = results[:num_build_numbers]
- times = times[:num_build_numbers]
- elif num_results < num_build_numbers:
- num_to_pad = num_build_numbers - num_results
- results = results + num_to_pad * self.NO_DATA_RESULT
- times.extend(num_to_pad * [0])
-
- test["results"] = results
- test["times"] = times
-
# Remove all passes/no-data from the results to reduce noise and filesize.
- if (results == num_build_numbers * self.NO_DATA_RESULT or
- (max(times) <= self.MIN_TIME and num_results and
- results == num_build_numbers * self.PASS_RESULT)):
+ if (self._IsResultsAllOfType(test[self.RESULTS], self.PASS_RESULT) or
+ (self._IsResultsAllOfType(test[self.RESULTS], self.NO_DATA_RESULT) and
+ max(test[self.TIMES],
+ lambda x, y : cmp(x[1], y[1])) <= self.MIN_TIME)):
del tests[test_path]
# Remove tests that don't exist anymore.
@@ -227,6 +276,11 @@
if not os.path.exists(full_path):
del tests[test_path]
+ def _IsResultsAllOfType(self, results, type):
+ """Returns whether all teh results are of the given type (e.g. all passes).
+ """
+ return len(results) == 1 and results[0][1] == type
+
class ResultAndTime:
"""A holder for a single result and runtime for a test."""
def __init__(self, test, all_tests):

Powered by Google App Engine
This is Rietveld 408576698