| 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 18 matching lines...) Expand all Loading... |
| 29 import copy | 29 import copy |
| 30 import logging | 30 import logging |
| 31 import functools | 31 import functools |
| 32 | 32 |
| 33 from webkitpy.common.memoized import memoized | 33 from webkitpy.common.memoized import memoized |
| 34 | 34 |
| 35 _log = logging.getLogger(__name__) | 35 _log = logging.getLogger(__name__) |
| 36 | 36 |
| 37 | 37 |
| 38 class BaselineOptimizer(object): | 38 class BaselineOptimizer(object): |
| 39 ROOT_LAYOUT_TESTS_DIRECTORY = 'LayoutTests' | |
| 40 | 39 |
| 41 def __init__(self, host, port, port_names): | 40 def __init__(self, host, port, port_names): |
| 42 self._filesystem = host.filesystem | 41 self._filesystem = host.filesystem |
| 43 self._default_port = port | 42 self._default_port = port |
| 44 self._ports = {} | 43 self._ports = {} |
| 45 for port_name in port_names: | 44 for port_name in port_names: |
| 46 self._ports[port_name] = host.port_factory.get(port_name) | 45 self._ports[port_name] = host.port_factory.get(port_name) |
| 47 | 46 |
| 48 self._webkit_base = port.webkit_base() | |
| 49 self._layout_tests_dir = port.layout_tests_dir() | 47 self._layout_tests_dir = port.layout_tests_dir() |
| 48 self._parent_of_tests = self._filesystem.dirname(self._layout_tests_dir) |
| 49 self._layout_tests_dir_name = self._filesystem.relpath( |
| 50 self._layout_tests_dir, self._parent_of_tests) |
| 50 | 51 |
| 51 # Only used by unit tests. | 52 # Only used by unit tests. |
| 52 self.new_results_by_directory = [] | 53 self.new_results_by_directory = [] |
| 53 | 54 |
| 54 def optimize(self, baseline_name): | 55 def optimize(self, baseline_name): |
| 55 # The virtual fallback path is the same as the non-virtual one | 56 # The virtual fallback path is the same as the non-virtual one |
| 56 # tacked on to the bottom of the non-virtual path. See | 57 # tacked on to the bottom of the non-virtual path. See |
| 57 # https://docs.google.com/a/chromium.org/drawings/d/1eGdsIKzJ2dxDDBbUaIA
BrN4aMLD1bqJTfyxNGZsTdmg/edit | 58 # https://docs.google.com/a/chromium.org/drawings/d/1eGdsIKzJ2dxDDBbUaIA
BrN4aMLD1bqJTfyxNGZsTdmg/edit |
| 58 # for a visual representation of this. | 59 # for a visual representation of this. |
| 59 # So, we can optimize the virtual path, then the virtual root, and then | 60 # So, we can optimize the virtual path, then the virtual root, and then |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 file_names.append(destination) | 152 file_names.append(destination) |
| 152 | 153 |
| 153 if file_names: | 154 if file_names: |
| 154 _log.debug(' Adding:') | 155 _log.debug(' Adding:') |
| 155 for platform_dir in sorted(self._platform(filename) for filename in
file_names): | 156 for platform_dir in sorted(self._platform(filename) for filename in
file_names): |
| 156 _log.debug(' ' + platform_dir) | 157 _log.debug(' ' + platform_dir) |
| 157 else: | 158 else: |
| 158 _log.debug(' (Nothing to add)') | 159 _log.debug(' (Nothing to add)') |
| 159 | 160 |
| 160 def _platform(self, filename): | 161 def _platform(self, filename): |
| 161 platform_dir = self.ROOT_LAYOUT_TESTS_DIRECTORY + self._filesystem.sep +
'platform' + self._filesystem.sep | 162 platform_dir = self._layout_tests_dir_name + self._filesystem.sep + 'pla
tform' + self._filesystem.sep |
| 162 if filename.startswith(platform_dir): | 163 if filename.startswith(platform_dir): |
| 163 return filename.replace(platform_dir, '').split(self._filesystem.sep
)[0] | 164 return filename.replace(platform_dir, '').split(self._filesystem.sep
)[0] |
| 164 platform_dir = self._filesystem.join(self._webkit_base, platform_dir) | 165 platform_dir = self._filesystem.join(self._parent_of_tests, platform_dir
) |
| 165 if filename.startswith(platform_dir): | 166 if filename.startswith(platform_dir): |
| 166 return filename.replace(platform_dir, '').split(self._filesystem.sep
)[0] | 167 return filename.replace(platform_dir, '').split(self._filesystem.sep
)[0] |
| 167 return '(generic)' | 168 return '(generic)' |
| 168 | 169 |
| 169 def _optimize_virtual_root(self, baseline_name, non_virtual_baseline_name): | 170 def _optimize_virtual_root(self, baseline_name, non_virtual_baseline_name): |
| 170 virtual_root_baseline_path = self._filesystem.join(self._layout_tests_di
r, baseline_name) | 171 virtual_root_baseline_path = self._filesystem.join(self._layout_tests_di
r, baseline_name) |
| 171 if not self._filesystem.exists(virtual_root_baseline_path): | 172 if not self._filesystem.exists(virtual_root_baseline_path): |
| 172 return | 173 return |
| 173 root_sha1 = self._filesystem.sha1(virtual_root_baseline_path) | 174 root_sha1 = self._filesystem.sha1(virtual_root_baseline_path) |
| 174 | 175 |
| 175 results_by_directory = self.read_results_by_directory(non_virtual_baseli
ne_name) | 176 results_by_directory = self.read_results_by_directory(non_virtual_baseli
ne_name) |
| 176 # See if all the immediate predecessors of the virtual root have the sam
e expected result. | 177 # See if all the immediate predecessors of the virtual root have the sam
e expected result. |
| 177 for port in self._ports.values(): | 178 for port in self._ports.values(): |
| 178 directories = self._relative_baseline_search_paths(port, non_virtual
_baseline_name) | 179 directories = self._relative_baseline_search_paths(port, non_virtual
_baseline_name) |
| 179 for directory in directories: | 180 for directory in directories: |
| 180 if directory not in results_by_directory: | 181 if directory not in results_by_directory: |
| 181 continue | 182 continue |
| 182 if results_by_directory[directory] != root_sha1: | 183 if results_by_directory[directory] != root_sha1: |
| 183 return | 184 return |
| 184 break | 185 break |
| 185 | 186 |
| 186 _log.debug('Deleting redundant virtual root expected result.') | 187 _log.debug('Deleting redundant virtual root expected result.') |
| 187 _log.debug(' Deleting (file system): ' + virtual_root_baseline_path) | 188 _log.debug(' Deleting (file system): ' + virtual_root_baseline_path) |
| 188 self._filesystem.remove(virtual_root_baseline_path) | 189 self._filesystem.remove(virtual_root_baseline_path) |
| 189 | 190 |
| 190 def _baseline_root(self, baseline_name): | 191 def _baseline_root(self, baseline_name): |
| 191 virtual_suite = self._virtual_suite(baseline_name) | 192 virtual_suite = self._virtual_suite(baseline_name) |
| 192 if virtual_suite: | 193 if virtual_suite: |
| 193 return self._filesystem.join(self.ROOT_LAYOUT_TESTS_DIRECTORY, virtu
al_suite.name) | 194 return self._filesystem.join(self._layout_tests_dir_name, virtual_su
ite.name) |
| 194 return self.ROOT_LAYOUT_TESTS_DIRECTORY | 195 return self._layout_tests_dir_name |
| 195 | 196 |
| 196 def _baseline_search_path(self, port, baseline_name): | 197 def _baseline_search_path(self, port, baseline_name): |
| 197 virtual_suite = self._virtual_suite(baseline_name) | 198 virtual_suite = self._virtual_suite(baseline_name) |
| 198 if virtual_suite: | 199 if virtual_suite: |
| 199 return port.virtual_baseline_search_path(baseline_name) | 200 return port.virtual_baseline_search_path(baseline_name) |
| 200 return port.baseline_search_path() | 201 return port.baseline_search_path() |
| 201 | 202 |
| 202 def _virtual_suite(self, baseline_name): | 203 def _virtual_suite(self, baseline_name): |
| 203 return self._default_port.lookup_virtual_suite(baseline_name) | 204 return self._default_port.lookup_virtual_suite(baseline_name) |
| 204 | 205 |
| 205 def _virtual_base(self, baseline_name): | 206 def _virtual_base(self, baseline_name): |
| 206 return self._default_port.lookup_virtual_test_base(baseline_name) | 207 return self._default_port.lookup_virtual_test_base(baseline_name) |
| 207 | 208 |
| 208 def _relative_baseline_search_paths(self, port, baseline_name): | 209 def _relative_baseline_search_paths(self, port, baseline_name): |
| 209 """Returns a list of paths to check for baselines in order.""" | 210 """Returns a list of paths to check for baselines in order.""" |
| 210 baseline_search_path = self._baseline_search_path(port, baseline_name) | 211 baseline_search_path = self._baseline_search_path(port, baseline_name) |
| 211 baseline_root = self._baseline_root(baseline_name) | 212 baseline_root = self._baseline_root(baseline_name) |
| 212 relative_paths = [self._filesystem.relpath(path, self._webkit_base) for
path in baseline_search_path] | 213 relative_paths = [self._filesystem.relpath(path, self._parent_of_tests)
for path in baseline_search_path] |
| 213 return relative_paths + [baseline_root] | 214 return relative_paths + [baseline_root] |
| 214 | 215 |
| 215 def _join_directory(self, directory, baseline_name): | 216 def _join_directory(self, directory, baseline_name): |
| 216 # This code is complicated because both the directory name and the | 217 # This code is complicated because both the directory name and the |
| 217 # baseline_name have the virtual test suite in the name and the virtual | 218 # baseline_name have the virtual test suite in the name and the virtual |
| 218 # baseline name is not a strict superset of the non-virtual name. | 219 # baseline name is not a strict superset of the non-virtual name. |
| 219 # For example, virtual/gpu/fast/canvas/foo-expected.png corresponds to | 220 # For example, virtual/gpu/fast/canvas/foo-expected.png corresponds to |
| 220 # fast/canvas/foo-expected.png and the baseline directories are like | 221 # fast/canvas/foo-expected.png and the baseline directories are like |
| 221 # platform/mac/virtual/gpu/fast/canvas. So, to get the path to the | 222 # platform/mac/virtual/gpu/fast/canvas. So, to get the path to the |
| 222 # baseline in the platform directory, we need to append just | 223 # baseline in the platform directory, we need to append just |
| 223 # foo-expected.png to the directory. | 224 # foo-expected.png to the directory. |
| 224 virtual_suite = self._virtual_suite(baseline_name) | 225 virtual_suite = self._virtual_suite(baseline_name) |
| 225 if virtual_suite: | 226 if virtual_suite: |
| 226 baseline_name_without_virtual = baseline_name[len(virtual_suite.name
) + 1:] | 227 baseline_name_without_virtual = baseline_name[len(virtual_suite.name
) + 1:] |
| 227 else: | 228 else: |
| 228 baseline_name_without_virtual = baseline_name | 229 baseline_name_without_virtual = baseline_name |
| 229 return self._filesystem.join(self._webkit_base, directory, baseline_name
_without_virtual) | 230 return self._filesystem.join(self._parent_of_tests, directory, baseline_
name_without_virtual) |
| 230 | 231 |
| 231 def _results_by_port_name(self, results_by_directory, baseline_name): | 232 def _results_by_port_name(self, results_by_directory, baseline_name): |
| 232 results_by_port_name = {} | 233 results_by_port_name = {} |
| 233 for port_name, port in self._ports.items(): | 234 for port_name, port in self._ports.items(): |
| 234 for directory in self._relative_baseline_search_paths(port, baseline
_name): | 235 for directory in self._relative_baseline_search_paths(port, baseline
_name): |
| 235 if directory in results_by_directory: | 236 if directory in results_by_directory: |
| 236 results_by_port_name[port_name] = results_by_directory[direc
tory] | 237 results_by_port_name[port_name] = results_by_directory[direc
tory] |
| 237 break | 238 break |
| 238 return results_by_port_name | 239 return results_by_port_name |
| 239 | 240 |
| 240 @memoized | 241 @memoized |
| 241 def _directories_immediately_preceding_root(self, baseline_name): | 242 def _directories_immediately_preceding_root(self, baseline_name): |
| 242 directories = set() | 243 directories = set() |
| 243 for port in self._ports.values(): | 244 for port in self._ports.values(): |
| 244 directory = self._filesystem.relpath(self._baseline_search_path(port
, baseline_name)[-1], self._webkit_base) | 245 directory = self._filesystem.relpath(self._baseline_search_path(port
, baseline_name)[-1], self._parent_of_tests) |
| 245 directories.add(directory) | 246 directories.add(directory) |
| 246 return directories | 247 return directories |
| 247 | 248 |
| 248 def _optimize_result_for_root(self, new_results_by_directory, baseline_name)
: | 249 def _optimize_result_for_root(self, new_results_by_directory, baseline_name)
: |
| 249 # The root directory (i.e. LayoutTests) is the only one that doesn't cor
respond | 250 # The root directory (i.e. LayoutTests) is the only one that doesn't cor
respond |
| 250 # to a specific platform. As such, it's the only one where the baseline
in fallback directories | 251 # to a specific platform. As such, it's the only one where the baseline
in fallback directories |
| 251 # immediately before it can be promoted up, i.e. if win and mac | 252 # immediately before it can be promoted up, i.e. if win and mac |
| 252 # have the same baseline, then it can be promoted up to be the LayoutTes
ts baseline. | 253 # have the same baseline, then it can be promoted up to be the LayoutTes
ts baseline. |
| 253 # All other baselines can only be removed if they're redundant with a ba
seline earlier | 254 # All other baselines can only be removed if they're redundant with a ba
seline earlier |
| 254 # in the fallback order. They can never promoted up. | 255 # in the fallback order. They can never promoted up. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 # The new_directory contains a different result, so stop try
ing to push results up. | 316 # The new_directory contains a different result, so stop try
ing to push results up. |
| 316 break | 317 break |
| 317 | 318 |
| 318 return new_results_by_directory | 319 return new_results_by_directory |
| 319 | 320 |
| 320 def _find_in_fallbackpath(self, fallback_path, current_result, results_by_di
rectory): | 321 def _find_in_fallbackpath(self, fallback_path, current_result, results_by_di
rectory): |
| 321 for index, directory in enumerate(fallback_path): | 322 for index, directory in enumerate(fallback_path): |
| 322 if directory in results_by_directory and (results_by_directory[direc
tory] == current_result): | 323 if directory in results_by_directory and (results_by_directory[direc
tory] == current_result): |
| 323 return index, directory | 324 return index, directory |
| 324 assert False, 'result %s not found in fallback_path %s, %s' % (current_r
esult, fallback_path, results_by_directory) | 325 assert False, 'result %s not found in fallback_path %s, %s' % (current_r
esult, fallback_path, results_by_directory) |
| OLD | NEW |