Diff
Modified: trunk/Tools/ChangeLog (238902 => 238903)
--- trunk/Tools/ChangeLog 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/ChangeLog 2018-12-05 19:30:47 UTC (rev 238903)
@@ -1,3 +1,56 @@
+2018-12-05 Jonathan Bedard <[email protected]>
+
+ webkitpy: Sort tests by associated device type
+ https://bugs.webkit.org/show_bug.cgi?id=192161
+ <rdar://problem/46345392>
+
+ Reviewed by Lucas Forschler.
+
+ Sort tests by device type and make an effort to run each specified device type.
+ Do not run tests if their specified device is not available.
+
+ * Scripts/webkitpy/common/system/platforminfo.py:
+ (PlatformInfo.is_watchos): Add watchos bits to platform info.
+ (PlatformInfo._determine_os_name): Ditto.
+ * Scripts/webkitpy/layout_tests/controllers/manager.py:
+ (Manager.run): Assign each test a device type. Then, generate a list of
+ device types to sequentially iterate through. Note that a test will run
+ on the first device which matches.
+ (Manager._end_test_run): Handle the case where no devices are available and no
+ tests are run.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ (_set_up_derived_options): Manage child processes in manager.
+ * Scripts/webkitpy/port/base.py:
+ (Port):
+ (Port.default_child_processes): Accept additional arguments.
+ (Port.max_child_processes): Add upper limit for number of child processes.
+ * Scripts/webkitpy/port/device_port.py:
+ (DevicePort):
+ (DevicePort._device_type_with_version): Adds version to the DeviceType.
+ (DevicePort.default_child_processes): Allows default_child_processes to be
+ attached to a device type.
+ (DevicePort.max_child_processes): Add upper limit to the maximum number of child processes.
+ (DevicePort.setup_test_run): Use _device_type_with_version.
+ * Scripts/webkitpy/port/ios_device.py:
+ (IOSDevicePort):
+ (IOSDevicePort.default_child_processes): Deleted.
+ * Scripts/webkitpy/port/ios_simulator.py:
+ (IOSSimulatorPort.default_child_processes): Deleted.
+ (IOSSimulatorPort.check_sys_deps): Deleted.
+ * Scripts/webkitpy/port/mac.py:
+ (MacPort.default_child_processes): Accept additional arguments.
+ * Scripts/webkitpy/port/test.py:
+ * Scripts/webkitpy/port/watch_device.py:
+ (WatchDevicePort):
+ (WatchDevicePort.default_child_processes): Deleted.
+ * Scripts/webkitpy/port/watch_simulator.py:
+ (WatchSimulatorPort.default_child_processes): Deleted.
+ (WatchSimulatorPort.check_sys_deps): Deleted.
+ * Scripts/webkitpy/xcode/simulated_device.py:
+ (SimulatedDeviceManager):
+ (SimulatedDeviceManager.device_count_for_type): Count the number of devices
+ available for a specific device type.
+
2018-12-05 Devin Rousso <[email protected]>
Unreviewed, add myself to some watch lists.
Modified: trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/common/system/platforminfo.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -72,6 +72,9 @@
def is_ios(self):
return self.os_name == 'ios'
+ def is_watchos(self):
+ return self.os_name == 'watchos'
+
def is_win(self):
return self.os_name == 'win'
@@ -179,7 +182,7 @@
def _determine_os_name(self, sys_platform):
if sys_platform == 'darwin':
return 'mac'
- if sys_platform == 'ios':
+ if sys_platform == 'ios' or sys_platform == 'watchos':
return 'ios'
if sys_platform.startswith('linux'):
return 'linux'
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -104,7 +104,6 @@
return self.web_platform_test_subdir in test or self.webkit_specific_web_platform_test_subdir in test
def _custom_device_for_test(self, test):
- # FIXME: Use available devices instead of CUSTOM_DEVICE_TYPES https://bugs.webkit.org/show_bug.cgi?id=192161
# FIXME: This is a terrible way to do device-specific expected results https://bugs.webkit.org/show_bug.cgi?id=192162
for device_type in self._port.CUSTOM_DEVICE_TYPES:
if device_type.hardware_family and device_type.hardware_family.lower() + self._port.TEST_PATH_SEPARATOR in test:
@@ -206,25 +205,25 @@
_log.critical('No tests to run.')
return test_run_results.RunDetails(exit_code=-1)
- default_device_tests = []
-
# Look for tests with custom device requirements.
- custom_device_tests = defaultdict(list)
+ test_device_mapping = defaultdict(list)
for test_file in tests_to_run:
- custom_device = self._custom_device_for_test(test_file)
- if custom_device:
- custom_device_tests[custom_device].append(test_file)
+ test_device_mapping[self._custom_device_for_test(test_file) or self._port.DEFAULT_DEVICE_TYPE].append(test_file)
+
+ # Order device types from most specific to least specific in the hopes that some of the more specific device
+ # types will match the less specific device types.
+ device_type_order = []
+ types_with_family = []
+ remaining_types = []
+ for device_type in test_device_mapping.iterkeys():
+ if device_type and device_type.hardware_family and device_type.hardware_type:
+ device_type_order.append(device_type)
+ elif device_type and device_type.hardware_family:
+ types_with_family.append(device_type)
else:
- default_device_tests.append(test_file)
+ remaining_types.append(device_type)
+ device_type_order.extend(types_with_family + remaining_types)
- if custom_device_tests:
- for device_type, tests in custom_device_tests.iteritems():
- _log.debug('{} tests use device {}'.format(len(tests), device_type))
-
- initial_results = None
- retry_results = None
- enabled_pixel_tests_in_retry = False
-
needs_http = any((self._is_http_test(test) and not self._needs_web_platform_test(test)) for test in tests_to_run)
needs_web_platform_test_server = any(self._needs_web_platform_test(test) for test in tests_to_run)
needs_websockets = any(self._is_websocket_test(test) for test in tests_to_run)
@@ -242,33 +241,48 @@
# Create the output directory if it doesn't already exist.
self._port.host.filesystem.maybe_make_directory(self._results_directory)
- if default_device_tests:
- _log.info('')
- _log.info("Running %s", pluralize(len(tests_to_run), "test"))
- _log.info('')
- if not self._set_up_run(tests_to_run):
- return test_run_results.RunDetails(exit_code=-1)
+ initial_results = None
+ retry_results = None
+ enabled_pixel_tests_in_retry = False
- initial_results, retry_results, enabled_pixel_tests_in_retry = self._run_test_subset(default_device_tests, tests_to_skip)
+ child_processes_option_value = self._options.child_processes
- # Only use a single worker for custom device classes
- self._options.child_processes = 1
- for device_type in custom_device_tests:
- device_tests = custom_device_tests[device_type]
- if device_tests:
+ while device_type_order:
+ device_type = device_type_order[0]
+ tests = test_device_mapping[device_type]
+ del device_type_order[0]
+
+ self._options.child_processes = min(self._port.max_child_processes(device_type=device_type), int(child_processes_option_value or self._port.default_child_processes(device_type=device_type)))
+
+ _log.info('')
+ if not self._options.child_processes:
+ _log.info('Skipping {} because {} is not available'.format(pluralize(len(test_device_mapping[device_type]), 'test'), str(device_type)))
_log.info('')
- _log.info('Running %s for %s', pluralize(len(device_tests), "test"), device_type)
- _log.info('')
- if not self._set_up_run(device_tests, device_type):
- return test_run_results.RunDetails(exit_code=-1)
+ continue
- device_initial_results, device_retry_results, device_enabled_pixel_tests_in_retry = self._run_test_subset(device_tests, tests_to_skip)
+ # This loop looks for any less-specific device types which match the current device type
+ index = 0
+ while index < len(device_type_order):
+ if device_type_order[index] == device_type:
+ tests.extend(test_device_mapping[device_type_order[index]])
- initial_results = initial_results.merge(device_initial_results) if initial_results else device_initial_results
- retry_results = retry_results.merge(device_retry_results) if retry_results else device_retry_results
- enabled_pixel_tests_in_retry |= device_enabled_pixel_tests_in_retry
+ # Remove devices types from device_type_order once tests associated with that type have been claimed.
+ del device_type_order[index]
+ else:
+ index += 1
+ _log.info('Running {}{}'.format(pluralize(len(tests), 'test'), ' for {}'.format(str(device_type)) if device_type else ''))
+ _log.info('')
+ if not self._set_up_run(tests, device_type):
+ return test_run_results.RunDetails(exit_code=-1)
+
+ temp_initial_results, temp_retry_results, temp_enabled_pixel_tests_in_retry = self._run_test_subset(tests, tests_to_skip)
+ initial_results = initial_results.merge(temp_initial_results) if initial_results else temp_initial_results
+ retry_results = retry_results.merge(temp_retry_results) if retry_results else temp_retry_results
+ enabled_pixel_tests_in_retry |= temp_enabled_pixel_tests_in_retry
+
self._runner.stop_servers()
+
end_time = time.time()
return self._end_test_run(start_time, end_time, initial_results, retry_results, enabled_pixel_tests_in_retry)
@@ -298,9 +312,12 @@
return (initial_results, retry_results, enabled_pixel_tests_in_retry)
def _end_test_run(self, start_time, end_time, initial_results, retry_results, enabled_pixel_tests_in_retry):
+ if initial_results is None:
+ _log.error('No results generated')
+ return test_run_results.RunDetails(exit_code=-1)
+
# Some crash logs can take a long time to be written out so look
# for new logs after the test run finishes.
-
_log.debug("looking for new crash logs")
self._look_for_new_crash_logs(initial_results, start_time)
if retry_results:
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -370,10 +370,6 @@
def _set_up_derived_options(port, options):
"""Sets the options values that depend on other options values."""
- if not options.child_processes:
- options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
- str(port.default_child_processes()))
-
if not options.configuration:
options.configuration = port.default_configuration()
Modified: trunk/Tools/Scripts/webkitpy/port/base.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/base.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/base.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -81,6 +81,7 @@
DEFAULT_ARCHITECTURE = 'x86'
+ DEFAULT_DEVICE_TYPE = None
CUSTOM_DEVICE_TYPES = []
@classmethod
@@ -176,10 +177,14 @@
def should_retry_crashes(self):
return False
- def default_child_processes(self):
+ def default_child_processes(self, **kwargs):
"""Return the number of DumpRenderTree instances to use for this port."""
return self._executive.cpu_count()
+ def max_child_processes(self, **kwargs):
+ """Forbid the user from specifying more than this number of child processes"""
+ return float('inf')
+
def worker_startup_delay_secs(self):
# FIXME: If we start workers up too quickly, DumpRenderTree appears
# to thrash on something and time out its first few tests. Until
Modified: trunk/Tools/Scripts/webkitpy/port/device_port.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/device_port.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/device_port.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -23,12 +23,11 @@
import logging
import traceback
-from webkitpy.common.memoized import memoized
from webkitpy.layout_tests.models.test_configuration import TestConfiguration
from webkitpy.port.darwin import DarwinPort
from webkitpy.port.simulator_process import SimulatorProcess
from webkitpy.xcode.device_type import DeviceType
-from webkitpy.xcode.simulated_device import DeviceRequest
+from webkitpy.xcode.simulated_device import DeviceRequest, SimulatedDeviceManager
_log = logging.getLogger(__name__)
@@ -37,7 +36,6 @@
class DevicePort(DarwinPort):
DEVICE_MANAGER = None
- DEFAULT_DEVICE_TYPE = None
NO_DEVICE_MANAGER = 'No device manager found for port'
def __init__(self, *args, **kwargs):
@@ -59,7 +57,6 @@
configurations.append(TestConfiguration(version=self.version_name(), architecture=architecture, build_type=build_type))
return configurations
- @memoized
def child_processes(self):
return int(self.get_option('child_processes'))
@@ -106,17 +103,36 @@
if not device.install_dylibs(self._build_path()):
raise RuntimeError('Failed to install dylibs at {} on device {}'.format(self._build_path(), device.udid))
- def setup_test_run(self, device_type=None):
- if not self.DEVICE_MANAGER:
- raise RuntimeError(self.NO_DEVICE_MANAGER)
-
+ def _device_type_with_version(self, device_type=None):
device_type = device_type if device_type else self.DEFAULT_DEVICE_TYPE
- device_type = DeviceType(
+ return DeviceType(
hardware_family=device_type.hardware_family,
hardware_type=device_type.hardware_type,
software_version=self.device_version(),
software_variant=device_type.software_variant,
)
+
+ def default_child_processes(self, device_type=None):
+ if not self.DEVICE_MANAGER:
+ raise RuntimeError(self.NO_DEVICE_MANAGER)
+ if self.DEVICE_MANAGER.INITIALIZED_DEVICES:
+ return len(self.DEVICE_MANAGER.INITIALIZED_DEVICES)
+ return self.DEVICE_MANAGER.device_count_for_type(
+ self._device_type_with_version(device_type),
+ host=self.host,
+ dedicated_simulators=not self.get_option('dedicated_simulators', False),
+ )
+
+ def max_child_processes(self, device_type=None):
+ if self.DEVICE_MANAGER == SimulatedDeviceManager:
+ return super(DevicePort, self).max_child_processes(device_type=device_type)
+ return self.default_child_processes(device_type=device_type)
+
+ def setup_test_run(self, device_type=None):
+ if not self.DEVICE_MANAGER:
+ raise RuntimeError(self.NO_DEVICE_MANAGER)
+
+ device_type = self._device_type_with_version(device_type)
_log.debug('\nCreating devices for {}'.format(device_type))
request = DeviceRequest(
@@ -125,7 +141,14 @@
use_existing_simulator=False,
allow_incomplete_match=True,
)
- self.DEVICE_MANAGER.initialize_devices([request] * self.child_processes(), self.host)
+ self.DEVICE_MANAGER.initialize_devices(
+ [request] * self.child_processes(),
+ self.host,
+ layout_test_dir=self.layout_tests_dir(),
+ pin=self.get_option('pin', None),
+ use_nfs=self.get_option('use_nfs', True),
+ reboot=self.get_option('reboot', False),
+ )
if not self.devices():
raise RuntimeError('No devices are available for testing')
Modified: trunk/Tools/Scripts/webkitpy/port/ios_device.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/ios_device.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/ios_device.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -44,12 +44,6 @@
NO_ON_DEVICE_TESTING = 'On-device testing is not supported in this configuration'
NO_DEVICE_MANAGER = NO_ON_DEVICE_TESTING
- @memoized
- def default_child_processes(self):
- if apple_additions():
- return apple_additions().ios_device_default_child_processes(self)
- return 1
-
def _driver_class(self):
if apple_additions():
return apple_additions().ios_device_driver()
@@ -92,13 +86,15 @@
if self.get_option('version'):
return Version.from_string(self.get_option('version'))
- if not apple_additions():
+ if not self.DEVICE_MANAGER:
raise RuntimeError(self.NO_ON_DEVICE_TESTING)
- if not self.devices():
+ if not self.DEVICE_MANAGER.available_devices(host=self.host):
raise RuntimeError('No devices are available')
version = None
- for device in self.devices():
+ for device in self.DEVICE_MANAGER.available_devices(host=self.host):
+ if not device.platform.is_ios():
+ continue
if not version:
version = device.platform.os_version
else:
Modified: trunk/Tools/Scripts/webkitpy/port/ios_simulator.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/ios_simulator.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/ios_simulator.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -58,19 +58,6 @@
return Version.from_string(self.get_option('version'))
return IOSSimulatorPort._version_from_name(self._name) if IOSSimulatorPort._version_from_name(self._name) else self.host.platform.xcode_sdk_version('iphonesimulator')
- @memoized
- def default_child_processes(self):
- def booted_ios_devices_filter(device):
- if not device.platform_device.is_booted_or_booting():
- return False
- return device.platform_device.device_type in DeviceType(software_variant='iOS', software_version=self.device_version())
-
- if not self.get_option('dedicated_simulators', False):
- num_booted_sims = len(SimulatedDeviceManager.device_by_filter(booted_ios_devices_filter, host=self.host))
- if num_booted_sims:
- return num_booted_sims
- return SimulatedDeviceManager.max_supported_simulators(self.host)
-
def clean_up_test_run(self):
super(IOSSimulatorPort, self).clean_up_test_run()
_log.debug("clean_up_test_run")
@@ -102,14 +89,6 @@
def operating_system(self):
return 'ios-simulator'
- def check_sys_deps(self):
- target_device_type = DeviceType(software_variant='iOS', software_version=self.device_version())
- for device in SimulatedDeviceManager.available_devices(self.host):
- if device.platform_device.device_type in target_device_type:
- return super(IOSSimulatorPort, self).check_sys_deps()
- _log.error('No Simulated device matching "{}" defined in Xcode iOS SDK'.format(str(target_device_type)))
- return False
-
def reset_preferences(self):
_log.debug("reset_preferences")
SimulatedDeviceManager.tear_down(self.host)
Modified: trunk/Tools/Scripts/webkitpy/port/mac.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/mac.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/mac.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -188,7 +188,7 @@
def is_mavericks(self):
return self._version == 'mavericks'
- def default_child_processes(self):
+ def default_child_processes(self, **kwargs):
default_count = super(MacPort, self).default_child_processes()
# FIXME: https://bugs.webkit.org/show_bug.cgi?id=95906 With too many WebProcess WK2 tests get stuck in resource contention.
Modified: trunk/Tools/Scripts/webkitpy/port/test.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/test.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/test.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -418,7 +418,7 @@
}
return [self._webkit_baseline_path(d) for d in search_paths[self.name()]]
- def default_child_processes(self):
+ def default_child_processes(self, **kwargs):
return 1
def worker_startup_delay_secs(self):
Modified: trunk/Tools/Scripts/webkitpy/port/watch_device.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/watch_device.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/watch_device.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -42,12 +42,6 @@
NO_ON_DEVICE_TESTING = 'On-device testing is not supported in this configuration'
NO_DEVICE_MANAGER = NO_ON_DEVICE_TESTING
- @memoized
- def default_child_processes(self):
- if apple_additions():
- return len(apple_additions().device_for_worker_number_map(self, software_variant='watchOS'))
- return 1
-
def _driver_class(self):
if apple_additions():
return apple_additions().device_driver()
@@ -90,13 +84,15 @@
if self.get_option('version'):
return Version.from_string(self.get_option('version'))
- if not apple_additions():
+ if not self.DEVICE_MANAGER:
raise RuntimeError(self.NO_ON_DEVICE_TESTING)
- if not apple_additions().device_for_worker_number_map(self, software_variant='watchOS'):
+ if not self.DEVICE_MANAGER.available_devices(host=self.host):
raise RuntimeError('No devices are available')
version = None
- for device in self.devices():
+ for device in self.DEVICE_MANAGER.available_devices(host=self.host):
+ if not device.platform.is_watchos():
+ continue
if not version:
version = device.platform.os_version
else:
Modified: trunk/Tools/Scripts/webkitpy/port/watch_simulator.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/port/watch_simulator.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/port/watch_simulator.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -71,30 +71,9 @@
new_environment[value] = inherited_env[value]
return new_environment
- @memoized
- def default_child_processes(self):
- def filter_booted_watchos_devices(device):
- if not device.platform_device.is_booted_or_booting():
- return False
- return device.platform_device.device_type in DeviceType(software_variant='watchOS', software_version=self.device_version())
-
- if not self.get_option('dedicated_simulators', False):
- num_booted_sims = len(SimulatedDeviceManager.device_by_filter(filter_booted_watchos_devices, host=self.host))
- if num_booted_sims:
- return num_booted_sims
- return SimulatedDeviceManager.max_supported_simulators(self.host)
-
def operating_system(self):
return 'watchos-simulator'
- def check_sys_deps(self):
- target_device_type = DeviceType(software_variant='watchOS', software_version=self.device_version())
- for device in SimulatedDeviceManager.available_devices(self.host):
- if device.platform_device.device_type in target_device_type:
- return super(WatchSimulatorPort, self).check_sys_deps()
- _log.error('No simulated device matching "{}" found in watchOS SDK'.format(str(target_device_type)))
- return False
-
def setup_environ_for_server(self, server_name=None):
_log.debug('Setting up environment for server on {}'.format(self.operating_system()))
env = super(WatchSimulatorPort, self).setup_environ_for_server(server_name)
Modified: trunk/Tools/Scripts/webkitpy/xcode/simulated_device.py (238902 => 238903)
--- trunk/Tools/Scripts/webkitpy/xcode/simulated_device.py 2018-12-05 19:21:23 UTC (rev 238902)
+++ trunk/Tools/Scripts/webkitpy/xcode/simulated_device.py 2018-12-05 19:30:47 UTC (rev 238903)
@@ -325,6 +325,20 @@
SimulatedDeviceManager.INITIALIZED_DEVICES.append(device)
@staticmethod
+ def device_count_for_type(device_type, host=SystemHost(), use_booted_simulator=True, **kwargs):
+ if not host.platform.is_mac():
+ return 0
+
+ if SimulatedDeviceManager.device_by_filter(lambda device: device.platform_device.is_booted_or_booting(), host=host) and use_booted_simulator:
+ filter = lambda device: device.platform_device.is_booted_or_booting() and device.platform_device.device_type in device_type
+ return len(SimulatedDeviceManager.device_by_filter(filter, host=host))
+
+ for name in SimulatedDeviceManager._device_identifier_to_name.itervalues():
+ if DeviceType.from_string(name) in device_type:
+ return SimulatedDeviceManager.max_supported_simulators(host)
+ return 0
+
+ @staticmethod
def initialize_devices(requests, host=SystemHost(), name_base='Managed', simulator_ui=True, timeout=SIMULATOR_BOOT_TIMEOUT, **kwargs):
if SimulatedDeviceManager.INITIALIZED_DEVICES is not None:
return SimulatedDeviceManager.INITIALIZED_DEVICES