Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (C) 2011, Google Inc. All rights reserved. | 1 # Copyright (C) 2011, Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 | 46 |
| 47 | 47 |
| 48 class BaselineOptimizer(object): | 48 class BaselineOptimizer(object): |
| 49 ROOT_LAYOUT_TESTS_DIRECTORY = 'LayoutTests' | 49 ROOT_LAYOUT_TESTS_DIRECTORY = 'LayoutTests' |
| 50 | 50 |
| 51 def __init__(self, host, port_names): | 51 def __init__(self, host, port_names): |
| 52 self._filesystem = host.filesystem | 52 self._filesystem = host.filesystem |
| 53 self._port_factory = host.port_factory | 53 self._port_factory = host.port_factory |
| 54 self._scm = host.scm() | 54 self._scm = host.scm() |
| 55 self._port_names = port_names | 55 self._port_names = port_names |
| 56 # Only used by unittests. | |
| 57 self.new_results_by_directory = [] | |
| 58 | |
| 59 def _baseline_root(self, port, baseline_name): | |
| 60 virtual_suite = port.lookup_virtual_suite(baseline_name) | |
| 61 if virtual_suite: | |
| 62 return self._filesystem.join(self.ROOT_LAYOUT_TESTS_DIRECTORY, virtu al_suite.name) | |
| 63 return self.ROOT_LAYOUT_TESTS_DIRECTORY | |
| 64 | |
| 65 def _baseline_search_path(self, port, baseline_name): | |
| 66 virtual_suite = port.lookup_virtual_suite(baseline_name) | |
| 67 if virtual_suite: | |
| 68 return port.virtual_baseline_search_path(baseline_name) | |
| 69 return port.baseline_search_path() | |
| 56 | 70 |
| 57 @memoized | 71 @memoized |
| 58 def _relative_baseline_search_paths(self, port_name): | 72 def _relative_baseline_search_paths(self, port_name, baseline_name): |
| 59 port = self._port_factory.get(port_name) | 73 port = self._port_factory.get(port_name) |
| 60 relative_paths = [self._filesystem.relpath(path, port.webkit_base()) for path in port.baseline_search_path()] | 74 relative_paths = [self._filesystem.relpath(path, port.webkit_base()) for path in self._baseline_search_path(port, baseline_name)] |
| 61 return relative_paths + [self.ROOT_LAYOUT_TESTS_DIRECTORY] | 75 return relative_paths + [self._baseline_root(port, baseline_name)] |
| 62 | 76 |
| 63 def read_results_by_directory(self, baseline_name): | 77 def read_results_by_directory(self, baseline_name): |
| 64 results_by_directory = {} | 78 results_by_directory = {} |
| 65 directories = reduce(set.union, map(set, [self._relative_baseline_search _paths(port_name) for port_name in self._port_names])) | 79 directories = reduce(set.union, map(set, [self._relative_baseline_search _paths(port_name, baseline_name) for port_name in self._port_names])) |
| 80 | |
| 81 virtual_suite = self._port_factory.get().lookup_virtual_suite(baseline_n ame) | |
| 82 if virtual_suite: | |
| 83 baseline_name_without_virtual = baseline_name[len(virtual_suite.name ) + 1:] | |
| 84 else: | |
| 85 baseline_name_without_virtual = baseline_name | |
|
abarth-chromium
2013/07/08 20:59:33
Can you add a comment with the example you wrote o
| |
| 86 | |
| 66 for directory in directories: | 87 for directory in directories: |
| 67 path = self._filesystem.join(self._scm.checkout_root, directory, bas eline_name) | 88 path = self._filesystem.join(self._scm.checkout_root, directory, bas eline_name_without_virtual) |
| 68 if self._filesystem.exists(path): | 89 if self._filesystem.exists(path): |
| 69 results_by_directory[directory] = self._filesystem.sha1(path) | 90 results_by_directory[directory] = self._filesystem.sha1(path) |
| 70 return results_by_directory | 91 return results_by_directory |
| 71 | 92 |
| 72 def _results_by_port_name(self, results_by_directory): | 93 def _results_by_port_name(self, results_by_directory, baseline_name): |
| 73 results_by_port_name = {} | 94 results_by_port_name = {} |
| 74 for port_name in self._port_names: | 95 for port_name in self._port_names: |
| 75 for directory in self._relative_baseline_search_paths(port_name): | 96 for directory in self._relative_baseline_search_paths(port_name, bas eline_name): |
| 76 if directory in results_by_directory: | 97 if directory in results_by_directory: |
| 77 results_by_port_name[port_name] = results_by_directory[direc tory] | 98 results_by_port_name[port_name] = results_by_directory[direc tory] |
| 78 break | 99 break |
| 79 return results_by_port_name | 100 return results_by_port_name |
| 80 | 101 |
| 81 @memoized | 102 @memoized |
| 82 def _directories_immediately_preceding_root(self): | 103 def _directories_immediately_preceding_root(self, baseline_name): |
| 83 directories = set() | 104 directories = set() |
| 84 for port_name in self._port_names: | 105 for port_name in self._port_names: |
| 85 port = self._port_factory.get(port_name) | 106 port = self._port_factory.get(port_name) |
| 86 directory = self._filesystem.relpath(port.baseline_search_path()[-1] , port.webkit_base()) | 107 directory = self._filesystem.relpath(self._baseline_search_path(port , baseline_name)[-1], port.webkit_base()) |
| 87 directories.add(directory) | 108 directories.add(directory) |
| 88 return directories | 109 return directories |
| 89 | 110 |
| 90 def _optimize_result_for_root(self, new_results_by_directory): | 111 def _optimize_result_for_root(self, new_results_by_directory, baseline_name) : |
| 91 # The root directory (i.e. LayoutTests) is the only one that doesn't cor respond | 112 # The root directory (i.e. LayoutTests) is the only one that doesn't cor respond |
| 92 # to a specific platform. As such, it's the only one where the baseline in fallback directories | 113 # to a specific platform. As such, it's the only one where the baseline in fallback directories |
| 93 # immediately before it can be promoted up, i.e. if win and mac | 114 # immediately before it can be promoted up, i.e. if win and mac |
| 94 # have the same baseline, then it can be promoted up to be the LayoutTes ts baseline. | 115 # have the same baseline, then it can be promoted up to be the LayoutTes ts baseline. |
| 95 # All other baselines can only be removed if they're redundant with a ba seline earlier | 116 # All other baselines can only be removed if they're redundant with a ba seline earlier |
| 96 # in the fallback order. They can never promoted up. | 117 # in the fallback order. They can never promoted up. |
| 97 directories_immediately_preceding_root = self._directories_immediately_p receding_root() | 118 directories_immediately_preceding_root = self._directories_immediately_p receding_root(baseline_name) |
| 98 | 119 |
| 99 shared_result = None | 120 shared_result = None |
| 100 root_baseline_unused = False | 121 root_baseline_unused = False |
| 101 for directory in directories_immediately_preceding_root: | 122 for directory in directories_immediately_preceding_root: |
| 102 this_result = new_results_by_directory.get(directory) | 123 this_result = new_results_by_directory.get(directory) |
| 103 | 124 |
| 104 # If any of these directories don't have a baseline, there's no opti mization we can do. | 125 # If any of these directories don't have a baseline, there's no opti mization we can do. |
| 105 if not this_result: | 126 if not this_result: |
| 106 return | 127 return |
| 107 | 128 |
| 108 if not shared_result: | 129 if not shared_result: |
| 109 shared_result = this_result | 130 shared_result = this_result |
| 110 elif shared_result != this_result: | 131 elif shared_result != this_result: |
| 111 root_baseline_unused = True | 132 root_baseline_unused = True |
| 112 | 133 |
| 134 baseline_root = self._baseline_root(self._port_factory.get(), baseline_n ame) | |
| 135 | |
| 113 # The root baseline is unused if all the directories immediately precedi ng the root | 136 # The root baseline is unused if all the directories immediately precedi ng the root |
| 114 # have a baseline, but have different baselines, so the baselines can't be promoted up. | 137 # have a baseline, but have different baselines, so the baselines can't be promoted up. |
| 115 if root_baseline_unused: | 138 if root_baseline_unused: |
| 116 if self.ROOT_LAYOUT_TESTS_DIRECTORY in new_results_by_directory: | 139 if baseline_root in new_results_by_directory: |
| 117 del new_results_by_directory[self.ROOT_LAYOUT_TESTS_DIRECTORY] | 140 del new_results_by_directory[baseline_root] |
| 118 return | 141 return |
| 119 | 142 |
| 120 new_results_by_directory[self.ROOT_LAYOUT_TESTS_DIRECTORY] = shared_resu lt | 143 new_results_by_directory[baseline_root] = shared_result |
| 121 for directory in directories_immediately_preceding_root: | 144 for directory in directories_immediately_preceding_root: |
| 122 del new_results_by_directory[directory] | 145 del new_results_by_directory[directory] |
| 123 | 146 |
| 124 def _find_optimal_result_placement(self, baseline_name): | 147 def _find_optimal_result_placement(self, baseline_name): |
| 125 results_by_directory = self.read_results_by_directory(baseline_name) | 148 results_by_directory = self.read_results_by_directory(baseline_name) |
| 126 results_by_port_name = self._results_by_port_name(results_by_directory) | 149 results_by_port_name = self._results_by_port_name(results_by_directory, baseline_name) |
| 127 port_names_by_result = _invert_dictionary(results_by_port_name) | 150 port_names_by_result = _invert_dictionary(results_by_port_name) |
| 128 | 151 |
| 129 new_results_by_directory = self._remove_redundant_results(results_by_dir ectory, results_by_port_name, port_names_by_result) | 152 new_results_by_directory = self._remove_redundant_results(results_by_dir ectory, results_by_port_name, port_names_by_result, baseline_name) |
| 130 self._optimize_result_for_root(new_results_by_directory) | 153 self._optimize_result_for_root(new_results_by_directory, baseline_name) |
| 131 | 154 |
| 132 return results_by_directory, new_results_by_directory | 155 return results_by_directory, new_results_by_directory |
| 133 | 156 |
| 134 def _remove_redundant_results(self, results_by_directory, results_by_port_na me, port_names_by_result): | 157 def _remove_redundant_results(self, results_by_directory, results_by_port_na me, port_names_by_result, baseline_name): |
| 135 new_results_by_directory = copy.copy(results_by_directory) | 158 new_results_by_directory = copy.copy(results_by_directory) |
| 136 for port_name in self._port_names: | 159 for port_name in self._port_names: |
| 137 current_result = results_by_port_name.get(port_name) | 160 current_result = results_by_port_name.get(port_name) |
| 138 | 161 |
| 139 # This happens if we're missing baselines for a port. | 162 # This happens if we're missing baselines for a port. |
| 140 if not current_result: | 163 if not current_result: |
| 141 continue; | 164 continue; |
| 142 | 165 |
| 143 fallback_path = self._relative_baseline_search_paths(port_name) | 166 fallback_path = self._relative_baseline_search_paths(port_name, base line_name) |
| 144 current_index, current_directory = self._find_in_fallbackpath(fallba ck_path, current_result, new_results_by_directory) | 167 current_index, current_directory = self._find_in_fallbackpath(fallba ck_path, current_result, new_results_by_directory) |
| 145 for index in range(current_index + 1, len(fallback_path)): | 168 for index in range(current_index + 1, len(fallback_path)): |
| 146 new_directory = fallback_path[index] | 169 new_directory = fallback_path[index] |
| 147 if not new_directory in new_results_by_directory: | 170 if not new_directory in new_results_by_directory: |
| 148 # No result for this baseline in this directory. | 171 # No result for this baseline in this directory. |
| 149 continue | 172 continue |
| 150 elif new_results_by_directory[new_directory] == current_result: | 173 elif new_results_by_directory[new_directory] == current_result: |
| 151 # Result for new_directory are redundant with the result ear lier in the fallback order. | 174 # Result for new_directory are redundant with the result ear lier in the fallback order. |
| 152 if current_directory in new_results_by_directory: | 175 if current_directory in new_results_by_directory: |
| 153 del new_results_by_directory[current_directory] | 176 del new_results_by_directory[current_directory] |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 203 for platform_dir in sorted(self._platform(filename) for filename in file_names): | 226 for platform_dir in sorted(self._platform(filename) for filename in file_names): |
| 204 _log.debug(" " + platform_dir) | 227 _log.debug(" " + platform_dir) |
| 205 self._scm.add_list(file_names) | 228 self._scm.add_list(file_names) |
| 206 else: | 229 else: |
| 207 _log.debug(" (Nothing to add)") | 230 _log.debug(" (Nothing to add)") |
| 208 | 231 |
| 209 def write_by_directory(self, results_by_directory, writer, indent): | 232 def write_by_directory(self, results_by_directory, writer, indent): |
| 210 for path in sorted(results_by_directory): | 233 for path in sorted(results_by_directory): |
| 211 writer("%s%s: %s" % (indent, self._platform(path), results_by_direct ory[path][0:6])) | 234 writer("%s%s: %s" % (indent, self._platform(path), results_by_direct ory[path][0:6])) |
| 212 | 235 |
| 213 def optimize(self, baseline_name): | 236 def _optimize_helper(self, baseline_name): |
|
abarth-chromium
2013/07/08 20:59:33
Is there a better name we can use here? Perhaps _
| |
| 214 basename = self._filesystem.basename(baseline_name) | 237 basename = self._filesystem.basename(baseline_name) |
| 215 results_by_directory, new_results_by_directory = self._find_optimal_resu lt_placement(baseline_name) | 238 results_by_directory, new_results_by_directory = self._find_optimal_resu lt_placement(baseline_name) |
| 216 | 239 |
| 217 if new_results_by_directory == results_by_directory: | 240 if new_results_by_directory == results_by_directory: |
| 218 if new_results_by_directory: | 241 if new_results_by_directory: |
| 219 _log.debug(" %s: (already optimal)" % basename) | 242 _log.debug(" %s: (already optimal)" % basename) |
| 220 self.write_by_directory(results_by_directory, _log.debug, " " ) | 243 self.write_by_directory(results_by_directory, _log.debug, " " ) |
| 221 else: | 244 else: |
| 222 _log.debug(" %s: (no baselines found)" % basename) | 245 _log.debug(" %s: (no baselines found)" % basename) |
| 223 # This is just used for unittests. Intentionally set it to the old d ata if we don't modify anything. | 246 # This is just used for unittests. Intentionally set it to the old d ata if we don't modify anything. |
| 224 self.new_results_by_directory = results_by_directory | 247 self.new_results_by_directory.append(results_by_directory) |
| 225 return True | 248 return True |
| 226 | 249 |
| 227 if self._results_by_port_name(results_by_directory) != self._results_by_ port_name(new_results_by_directory): | 250 if self._results_by_port_name(results_by_directory, baseline_name) != se lf._results_by_port_name(new_results_by_directory, baseline_name): |
| 228 # This really should never happen. Just a sanity check to make sure the script fails in the case of bugs | 251 # This really should never happen. Just a sanity check to make sure the script fails in the case of bugs |
| 229 # instead of committing incorrect baselines. | 252 # instead of committing incorrect baselines. |
| 230 _log.error(" %s: optimization failed" % basename) | 253 _log.error(" %s: optimization failed" % basename) |
| 231 self.write_by_directory(results_by_directory, _log.warning, " " ) | 254 self.write_by_directory(results_by_directory, _log.warning, " " ) |
| 232 return False | 255 return False |
| 233 | 256 |
| 234 _log.debug(" %s:" % basename) | 257 _log.debug(" %s:" % basename) |
| 235 _log.debug(" Before: ") | 258 _log.debug(" Before: ") |
| 236 self.write_by_directory(results_by_directory, _log.debug, " ") | 259 self.write_by_directory(results_by_directory, _log.debug, " ") |
| 237 _log.debug(" After: ") | 260 _log.debug(" After: ") |
| 238 self.write_by_directory(new_results_by_directory, _log.debug, " ") | 261 self.write_by_directory(new_results_by_directory, _log.debug, " ") |
| 239 | 262 |
| 240 self._move_baselines(baseline_name, results_by_directory, new_results_by _directory) | 263 self._move_baselines(baseline_name, results_by_directory, new_results_by _directory) |
| 241 return True | 264 return True |
| 265 | |
| 266 def _optimize_virtual_root(self, baseline_name, non_virtual_baseline_name): | |
| 267 default_port = self._port_factory.get() | |
| 268 virtual_root_expected_baseline_path = self._filesystem.join(default_port .layout_tests_dir(), baseline_name) | |
| 269 if not self._filesystem.exists(virtual_root_expected_baseline_path): | |
| 270 return | |
| 271 root_sha1 = self._filesystem.sha1(virtual_root_expected_baseline_path) | |
| 272 | |
| 273 results_by_directory = self.read_results_by_directory(non_virtual_baseli ne_name) | |
| 274 # See if all the immediate predecessors of the virtual root have the sam e expected result. | |
| 275 for port_name in self._port_names: | |
| 276 directories = self._relative_baseline_search_paths(port_name, baseli ne_name) | |
| 277 for directory in directories: | |
| 278 if directory not in results_by_directory: | |
| 279 continue | |
| 280 if results_by_directory[directory] != root_sha1: | |
| 281 return | |
| 282 break | |
| 283 | |
| 284 _log.debug("Deleting redundant firtual root expected result.") | |
| 285 self._scm.delete(virtual_root_expected_baseline_path) | |
| 286 | |
| 287 def optimize(self, baseline_name): | |
| 288 _log.debug("Optimizing regular fallback path.") | |
| 289 result = self._optimize_helper(baseline_name) | |
| 290 non_virtual_baseline_name = self._port_factory.get().lookup_virtual_test _base(baseline_name) | |
| 291 if not non_virtual_baseline_name: | |
| 292 return result | |
| 293 | |
| 294 self._optimize_virtual_root(baseline_name, non_virtual_baseline_name) | |
| 295 | |
| 296 _log.debug("Optimizing non-virtual fallback path.") | |
| 297 result |= self._optimize_helper(non_virtual_baseline_name) | |
| 298 return result | |
| OLD | NEW |