<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[213236] trunk/Tools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/213236">213236</a></dd>
<dt>Author</dt> <dd>jbedard@apple.com</dd>
<dt>Date</dt> <dd>2017-03-01 11:47:21 -0800 (Wed, 01 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>webkitpy: Move some device management from iOSSimulatorPort to iOSPort class
https://bugs.webkit.org/show_bug.cgi?id=168681

Reviewed by Daniel Bates.

This patch moves high-level device management into iOSPort and adds a new iOSDevicePort class
which inherits from iOSPort.  Additionally, this change renames device_id_for_worker_number to
device_for_worker_number and manages devices by object instead of by UDID.

* Scripts/webkitpy/port/factory.py:
(PortFactory): Correct import path for IOSSimulatorPort and IOSDevicePort.
* Scripts/webkitpy/port/ios.py:
(IOSPort.__init__): Define variables shared between iOS ports.
(IOSPort.driver_cmd_line_for_logging): From IOSSimulatorPort.
(IOSPort.driver_name): From IOSSimulatorPort.
(IOSPort.using_multiple_devices): Check if this port supports multiple devices.
(IOSPort._testing_device): Map worker number to device.
(IOSPort.device_for_worker_number): Return _testing_device() or _current_device based on using_multiple_devices.
(IOSSimulatorPort): Moved to ios_simulator.py
* Scripts/webkitpy/port/ios_device.py: Added.
(IOSDevicePort): Moved functionality from IOSPort.
(IOSDevicePort.determine_full_port_name): Moved from IOSPort.
(IOSDevicePort._build_driver_flags): Ditto.
(IOSDevicePort.operating_system): Ditto.
* Scripts/webkitpy/port/ios_simulator.py: Added.
(IOSSimulatorPort): Moved from ios.py.
(IOSSimulatorPort.__init__): Init parent class, setup device map.
(IOSSimulatorPort._create_simulators): Use object over unbound methods.
(IOSSimulatorPort.setup_test_run): Ditto.
(IOSSimulatorPort.using_multiple_devices): True if we are managing the simulators.
(IOSSimulatorPort._create_device): Use object over unbound methods.
(IOSSimulatorPort._remove_device): Ditto.
(IOSSimulatorPort.driver_name): Moved to parent class.
(IOSSimulatorPort.driver_cmd_line_for_logging): Ditto.
(IOSSimulatorPort.child_processes): Ditto.
(IOSSimulatorPort._testing_device): Ditto.
(IOSSimulatorPort.device_id_for_worker_number): Renamed as device_for_worker_number.
(SimulatorProcess.__init__): Call find_device_by_udid, device_id_for_worker_number has been removed.
* Scripts/webkitpy/xcode/simulator.py:
(Simulator): Make _managed_devices public.
(Simulator.create_device): Ditto.
(Simulator.remove_device): Ditto.
(Simulator.device_number): Ditto.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptswebkitpyportfactorypy">trunk/Tools/Scripts/webkitpy/port/factory.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportiospy">trunk/Tools/Scripts/webkitpy/port/ios.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportios_unittestpy">trunk/Tools/Scripts/webkitpy/port/ios_unittest.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportsimulator_processpy">trunk/Tools/Scripts/webkitpy/port/simulator_process.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyxcodesimulatorpy">trunk/Tools/Scripts/webkitpy/xcode/simulator.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsScriptswebkitpyportios_devicepy">trunk/Tools/Scripts/webkitpy/port/ios_device.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportios_simulatorpy">trunk/Tools/Scripts/webkitpy/port/ios_simulator.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (213235 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-03-01 19:41:56 UTC (rev 213235)
+++ trunk/Tools/ChangeLog        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -1,3 +1,49 @@
</span><ins>+2017-03-01  Jonathan Bedard  &lt;jbedard@apple.com&gt;
+
+        webkitpy: Move some device management from iOSSimulatorPort to iOSPort class
+        https://bugs.webkit.org/show_bug.cgi?id=168681
+
+        Reviewed by Daniel Bates.
+
+        This patch moves high-level device management into iOSPort and adds a new iOSDevicePort class
+        which inherits from iOSPort.  Additionally, this change renames device_id_for_worker_number to
+        device_for_worker_number and manages devices by object instead of by UDID.
+
+        * Scripts/webkitpy/port/factory.py:
+        (PortFactory): Correct import path for IOSSimulatorPort and IOSDevicePort.
+        * Scripts/webkitpy/port/ios.py:
+        (IOSPort.__init__): Define variables shared between iOS ports.
+        (IOSPort.driver_cmd_line_for_logging): From IOSSimulatorPort.
+        (IOSPort.driver_name): From IOSSimulatorPort.
+        (IOSPort.using_multiple_devices): Check if this port supports multiple devices.
+        (IOSPort._testing_device): Map worker number to device.
+        (IOSPort.device_for_worker_number): Return _testing_device() or _current_device based on using_multiple_devices. 
+        (IOSSimulatorPort): Moved to ios_simulator.py
+        * Scripts/webkitpy/port/ios_device.py: Added.
+        (IOSDevicePort): Moved functionality from IOSPort.
+        (IOSDevicePort.determine_full_port_name): Moved from IOSPort.
+        (IOSDevicePort._build_driver_flags): Ditto.
+        (IOSDevicePort.operating_system): Ditto.
+        * Scripts/webkitpy/port/ios_simulator.py: Added.
+        (IOSSimulatorPort): Moved from ios.py.
+        (IOSSimulatorPort.__init__): Init parent class, setup device map.
+        (IOSSimulatorPort._create_simulators): Use object over unbound methods.
+        (IOSSimulatorPort.setup_test_run): Ditto.
+        (IOSSimulatorPort.using_multiple_devices): True if we are managing the simulators.
+        (IOSSimulatorPort._create_device): Use object over unbound methods.
+        (IOSSimulatorPort._remove_device): Ditto.
+        (IOSSimulatorPort.driver_name): Moved to parent class.
+        (IOSSimulatorPort.driver_cmd_line_for_logging): Ditto.
+        (IOSSimulatorPort.child_processes): Ditto.
+        (IOSSimulatorPort._testing_device): Ditto.
+        (IOSSimulatorPort.device_id_for_worker_number): Renamed as device_for_worker_number.
+        (SimulatorProcess.__init__): Call find_device_by_udid, device_id_for_worker_number has been removed.
+        * Scripts/webkitpy/xcode/simulator.py:
+        (Simulator): Make _managed_devices public.
+        (Simulator.create_device): Ditto.
+        (Simulator.remove_device): Ditto.
+        (Simulator.device_number): Ditto.
+
</ins><span class="cx"> 2017-03-01  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         IndexedDB.IndexedDBMultiProcess is a flaky timeout
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportfactorypy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/factory.py (213235 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/factory.py        2017-03-01 19:41:56 UTC (rev 213235)
+++ trunk/Tools/Scripts/webkitpy/port/factory.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -80,17 +80,17 @@
</span><span class="cx"> class PortFactory(object):
</span><span class="cx">     # Order matters.  For port classes that have a port_name with a
</span><span class="cx">     # common prefix, the more specific port class should be listed
</span><del>-    # first.  For example, 'ios.IOSSimulatorPort' (port_name='ios-simulator')
-    # should be listed before 'ios.IOSPort' (port_name='ios').  If this
</del><ins>+    # first.  For example, 'ios_simulator.IOSSimulatorPort' (port_name='ios-simulator')
+    # should be listed before 'ios_device.IOSDevicePort' (port_name='ios').  If this
</ins><span class="cx">     # rule is not followed, then `webkit-patch --ios-simulator` will try
</span><del>-    # to use IOSPort instead of IOSSimulatorPort because 'ios'
-    # (IOSPort.port_name) is a prefix of 'ios-simulator' (port_name
</del><ins>+    # to use IOSDevicePort instead of IOSSimulatorPort because 'ios'
+    # (IOSDevicePort.port_name) is a prefix of 'ios-simulator' (port_name
</ins><span class="cx">     # derived from '--ios-simulator' command-line switch), for example.
</span><span class="cx">     PORT_CLASSES = (
</span><span class="cx">         'efl.EflPort',
</span><span class="cx">         'gtk.GtkPort',
</span><del>-        'ios.IOSSimulatorPort',
-        'ios.IOSPort',
</del><ins>+        'ios_simulator.IOSSimulatorPort',
+        'ios_device.IOSDevicePort',
</ins><span class="cx">         'mac.MacPort',
</span><span class="cx">         'mock_drt.MockDRTPort',
</span><span class="cx">         'test.TestPort',
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportiospy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/ios.py (213235 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios.py        2017-03-01 19:41:56 UTC (rev 213235)
+++ trunk/Tools/Scripts/webkitpy/port/ios.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-# Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</del><ins>+# Copyright (C) 2014-2017 Apple Inc. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Redistribution and use in source and binary forms, with or without
</span><span class="cx"> # modification, are permitted provided that the following conditions
</span><span class="lines">@@ -20,25 +20,12 @@
</span><span class="cx"> # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
</span><span class="cx"> # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx"> 
</span><del>-import itertools
</del><span class="cx"> import logging
</span><del>-import os
-import re
-import shutil
-import subprocess
-import time
</del><span class="cx"> 
</span><span class="cx"> from webkitpy.common.memoized import memoized
</span><del>-from webkitpy.common.system.executive import ScriptError
-from webkitpy.layout_tests.models.test_configuration import TestConfiguration
-from webkitpy.port import config as port_config
-from webkitpy.port import driver, image_diff
</del><span class="cx"> from webkitpy.port.darwin import DarwinPort
</span><span class="cx"> from webkitpy.port.simulator_process import SimulatorProcess
</span><del>-from webkitpy.xcode.simulator import Simulator, Runtime, DeviceType
-from webkitpy.common.system.crashlogs import CrashLogs
</del><span class="cx"> 
</span><del>-
</del><span class="cx"> _log = logging.getLogger(__name__)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -45,73 +32,22 @@
</span><span class="cx"> class IOSPort(DarwinPort):
</span><span class="cx">     port_name = &quot;ios&quot;
</span><span class="cx"> 
</span><del>-    ARCHITECTURES = ['armv7', 'armv7s', 'arm64']
-    DEFAULT_ARCHITECTURE = 'arm64'
-    VERSION_FALLBACK_ORDER = ['ios-7', 'ios-8', 'ios-9', 'ios-10']
-
-    @classmethod
-    def determine_full_port_name(cls, host, options, port_name):
-        if port_name == cls.port_name:
-            iphoneos_sdk_version = host.platform.xcode_sdk_version('iphoneos')
-            if not iphoneos_sdk_version:
-                raise Exception(&quot;Please install the iOS SDK.&quot;)
-            major_version_number = iphoneos_sdk_version.split('.')[0]
-            port_name = port_name + '-' + major_version_number
-        return port_name
-
-    # Despite their names, these flags do not actually get passed all the way down to webkit-build.
-    def _build_driver_flags(self):
-        return ['--sdk', 'iphoneos'] + (['ARCHS=%s' % self.architecture()] if self.architecture() else [])
-
-    def operating_system(self):
-        return 'ios'
-
-
-class IOSSimulatorPort(DarwinPort):
-    port_name = &quot;ios-simulator&quot;
-
-    FUTURE_VERSION = 'future'
-    ARCHITECTURES = ['x86_64', 'x86']
-    DEFAULT_ARCHITECTURE = 'x86_64'
-
-    DEFAULT_DEVICE_CLASS = 'iphone'
-    CUSTOM_DEVICE_CLASSES = ['ipad', 'iphone7']
-    SDK = 'iphonesimulator'
-
-    SIMULATOR_BUNDLE_ID = 'com.apple.iphonesimulator'
-    SIMULATOR_DIRECTORY = &quot;/tmp/WebKitTestingSimulators/&quot;
-    LSREGISTER_PATH = &quot;/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister&quot;
-    PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE = 100
-
-    DEVICE_CLASS_MAP = {
-        'x86_64': {
-            'iphone': 'iPhone 5s',
-            'iphone7': 'iPhone 7',
-            'ipad': 'iPad Air'
-        },
-        'x86': {
-            'iphone': 'iPhone 5',
-            'ipad': 'iPad Retina'
-        },
-    }
-
</del><span class="cx">     def __init__(self, host, port_name, **kwargs):
</span><del>-        DarwinPort.__init__(self, host, port_name, **kwargs)
</del><ins>+        super(IOSPort, self).__init__(host, port_name, **kwargs)
</ins><span class="cx">         self._test_runner_process_constructor = SimulatorProcess
</span><ins>+        self._printing_cmd_line = False
+        self._current_device = None
</ins><span class="cx"> 
</span><del>-        optional_device_class = self.get_option('device_class')
</del><ins>+    def _device_for_worker_number_map(self):
+        raise NotImplementedError
+
+    def driver_cmd_line_for_logging(self):
+        # Avoid creating/connecting to devices just for logging the commandline.
+        self._printing_cmd_line = True
+        result = super(IOSPort, self).driver_cmd_line_for_logging()
</ins><span class="cx">         self._printing_cmd_line = False
</span><del>-        self._device_class = optional_device_class if optional_device_class else self.DEFAULT_DEVICE_CLASS
-        _log.debug('IOSSimulatorPort _device_class is %s', self._device_class)
</del><ins>+        return result
</ins><span class="cx"> 
</span><del>-        self._current_device = Simulator(host).current_device()
-        if not self._current_device:
-            self.set_option('dedicated_simulators', True)
-        if not self.get_option('dedicated_simulators'):
-            if self.get_option('child_processes') &gt; 1:
-                _log.warn('Cannot have more than one child process when using a running simulator.  Setting child_processes to 1.')
-            self.set_option('child_processes', 1)
-
</del><span class="cx">     def driver_name(self):
</span><span class="cx">         if self.get_option('driver_name'):
</span><span class="cx">             return self.get_option('driver_name')
</span><span class="lines">@@ -119,315 +55,24 @@
</span><span class="cx">             return 'WebKitTestRunnerApp.app'
</span><span class="cx">         return 'DumpRenderTree.app'
</span><span class="cx"> 
</span><del>-    def driver_cmd_line_for_logging(self):
-        # Avoid spinning up devices just for logging the commandline.
-        self._printing_cmd_line = True
-        result = super(IOSSimulatorPort, self).driver_cmd_line_for_logging()
-        self._printing_cmd_line = False
-        return result
-
-    @property
</del><span class="cx">     @memoized
</span><del>-    def simulator_runtime(self):
-        runtime_identifier = self.get_option('runtime')
-        if runtime_identifier:
-            runtime = Runtime.from_identifier(runtime_identifier)
-        else:
-            runtime = Runtime.from_version_string(self.host.platform.xcode_sdk_version('iphonesimulator'))
-        return runtime
-
-    def simulator_device_type(self):
-        device_type_identifier = self.get_option('device_type')
-        if device_type_identifier:
-            _log.debug('simulator_device_type for device identifier %s', device_type_identifier)
-            device_type = DeviceType.from_identifier(device_type_identifier)
-        else:
-            _log.debug('simulator_device_type for device %s', self._device_class)
-            device_name = self.DEVICE_CLASS_MAP[self.architecture()][self._device_class]
-            if not device_name:
-                raise Exception('Failed to find device for architecture {} and device class {}'.format(self.architecture()), self._device_class)
-            device_type = DeviceType.from_name(device_name)
-        return device_type
-
-    @memoized
</del><span class="cx">     def child_processes(self):
</span><span class="cx">         return int(self.get_option('child_processes'))
</span><span class="cx"> 
</span><del>-    @memoized
-    def default_child_processes(self):
-        &quot;&quot;&quot;Return the number of Simulators instances to use for this port.&quot;&quot;&quot;
-        best_child_process_count_for_cpu = self._executive.cpu_count() / 2
-        system_process_count_limit = int(subprocess.check_output([&quot;ulimit&quot;, &quot;-u&quot;]).strip())
-        current_process_count = len(subprocess.check_output([&quot;ps&quot;, &quot;aux&quot;]).strip().split('\n'))
-        _log.debug('Process limit: %d, current #processes: %d' % (system_process_count_limit, current_process_count))
-        maximum_simulator_count_on_this_system = (system_process_count_limit - current_process_count) // self.PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE
-        # FIXME: We should also take into account the available RAM.
</del><ins>+    def using_multiple_devices(self):
+        return False
</ins><span class="cx"> 
</span><del>-        if (maximum_simulator_count_on_this_system &lt; best_child_process_count_for_cpu):
-            _log.warn(&quot;This machine could support %s simulators, but is only configured for %s.&quot;
-                % (best_child_process_count_for_cpu, maximum_simulator_count_on_this_system))
-            _log.warn('Please see &lt;https://trac.webkit.org/wiki/IncreasingKernelLimits&gt;.')
-
-        if maximum_simulator_count_on_this_system == 0:
-            maximum_simulator_count_on_this_system = 1
-
-        return min(maximum_simulator_count_on_this_system, best_child_process_count_for_cpu)
-
-    def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=time.time, sleep_fn=time.sleep, wait_for_log=True):
-        time_fn = time_fn or time.time
-        sleep_fn = sleep_fn or time.sleep
-
-        # FIXME: We should collect the actual crash log for DumpRenderTree.app because it includes more
-        # information (e.g. exception codes) than is available in the stack trace written to standard error.
-        stderr_lines = []
-        crashed_subprocess_name_and_pid = None  # e.g. ('DumpRenderTree.app', 1234)
-        for line in (stderr or '').splitlines():
-            if not crashed_subprocess_name_and_pid:
-                match = self.SUBPROCESS_CRASH_REGEX.match(line)
-                if match:
-                    crashed_subprocess_name_and_pid = (match.group('subprocess_name'), int(match.group('subprocess_pid')))
-                    continue
-            stderr_lines.append(line)
-
-        if crashed_subprocess_name_and_pid:
-            return self._get_crash_log(crashed_subprocess_name_and_pid[0], crashed_subprocess_name_and_pid[1], stdout,
-                '\n'.join(stderr_lines), newer_than, time_fn, sleep_fn, wait_for_log)
-
-        # App crashed
-        _log.debug('looking for crash log for %s:%s' % (name, str(pid)))
-        crash_log = ''
-        crash_logs = CrashLogs(self.host)
-        now = time_fn()
-        deadline = now + 5 * int(self.get_option('child_processes', 1))
-        while not crash_log and now &lt;= deadline:
-            crash_log = crash_logs.find_newest_log(name, pid, include_errors=True, newer_than=newer_than)
-            if not wait_for_log:
-                break
-            if not crash_log or not [line for line in crash_log.splitlines() if not line.startswith('ERROR')]:
-                sleep_fn(0.1)
-                now = time_fn()
-
-        if not crash_log:
-            return stderr, None
-        return stderr, crash_log
-
-    def _build_driver_flags(self):
-        archs = ['ARCHS=i386'] if self.architecture() == 'x86' else []
-        sdk = ['--sdk', 'iphonesimulator']
-        return archs + sdk
-
-    def _generate_all_test_configurations(self):
-        configurations = []
-        for build_type in self.ALL_BUILD_TYPES:
-            for architecture in self.ARCHITECTURES:
-                configurations.append(TestConfiguration(version=self._version, architecture=architecture, build_type=build_type))
-        return configurations
-
-    def default_baseline_search_path(self):
-        if self.get_option('webkit_test_runner'):
-            fallback_names = [self._wk2_port_name()] + [self.port_name] + ['wk2']
-        else:
-            fallback_names = [self.port_name + '-wk1'] + [self.port_name]
-
-        return map(self._webkit_baseline_path, fallback_names)
-
-    def _set_device_class(self, device_class):
-        self._device_class = device_class if device_class else self.DEFAULT_DEVICE_CLASS
-
-    def _create_simulators(self):
-        if (self.default_child_processes() &lt; self.child_processes()):
-            _log.warn('You have specified very high value({0}) for --child-processes'.format(self.child_processes()))
-            _log.warn('maximum child-processes which can be supported on this system are: {0}'.format(self.default_child_processes()))
-            _log.warn('This is very likely to fail.')
-
-        if self._using_dedicated_simulators():
-            self._createSimulatorApps()
-
-            for i in xrange(self.child_processes()):
-                self._create_device(i)
-
-            for i in xrange(self.child_processes()):
-                device_udid = self._testing_device(i).udid
-                Simulator.wait_until_device_is_in_state(device_udid, Simulator.DeviceState.SHUTDOWN)
-                Simulator.reset_device(device_udid)
-        else:
-            assert(self._current_device)
-            if self._current_device.name != self.simulator_device_type().name:
-                _log.warn(&quot;Expected simulator of type '&quot; + self.simulator_device_type().name + &quot;' but found simulator of type '&quot; + self._current_device.name + &quot;'&quot;)
-                _log.warn('The next block of tests may fail due to device mis-match')
-
-    def setup_test_run(self, device_class=None):
-        mac_os_version = self.host.platform.os_version
-
-        self._set_device_class(device_class)
-
-        _log.debug('')
-        _log.debug('setup_test_run for %s', self._device_class)
-
-        self._create_simulators()
-
-        if not self._using_dedicated_simulators():
-            return
-
-        for i in xrange(self.child_processes()):
-            device_udid = self._testing_device(i).udid
-            _log.debug('testing device %s has udid %s', i, device_udid)
-
-            # FIXME: &lt;rdar://problem/20916140&gt; Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
-            self._executive.run_command([
-                'open', '-g', '-b', self.SIMULATOR_BUNDLE_ID + str(i),
-                '--args', '-CurrentDeviceUDID', device_udid])
-
-            if mac_os_version in ['elcapitan', 'yosemite', 'mavericks']:
-                time.sleep(2.5)
-
-        _log.info('Waiting for all iOS Simulators to finish booting.')
-        for i in xrange(self.child_processes()):
-            Simulator.wait_until_device_is_booted(self._testing_device(i).udid)
-
-    def _quit_ios_simulator(self):
-        if not self._using_dedicated_simulators():
-            return
-        _log.debug(&quot;_quit_ios_simulator killing all Simulator processes&quot;)
-        # FIXME: We should kill only the Simulators we started.
-        subprocess.call([&quot;killall&quot;, &quot;-9&quot;, &quot;-m&quot;, &quot;Simulator&quot;])
-
-    def clean_up_test_run(self):
-        super(IOSSimulatorPort, self).clean_up_test_run()
-        _log.debug(&quot;clean_up_test_run&quot;)
-        self._quit_ios_simulator()
-        fifos = [path for path in os.listdir('/tmp') if re.search('org.webkit.(DumpRenderTree|WebKitTestRunner).*_(IN|OUT|ERROR)', path)]
-        for fifo in fifos:
-            try:
-                os.remove(os.path.join('/tmp', fifo))
-            except OSError:
-                _log.warning('Unable to remove ' + fifo)
-                pass
-
-        if not self._using_dedicated_simulators():
-            return
-
-        for i in xrange(self.child_processes()):
-            simulator_path = self.get_simulator_path(i)
-            device_udid = self._testing_device(i).udid
-            self._remove_device(i)
-
-            if not os.path.exists(simulator_path):
-                continue
-            try:
-                self._executive.run_command([self.LSREGISTER_PATH, &quot;-u&quot;, simulator_path])
-
-                _log.debug('rmtree %s', simulator_path)
-                self._filesystem.rmtree(simulator_path)
-
-                logs_path = self._filesystem.join(self._filesystem.expanduser(&quot;~&quot;), &quot;Library/Logs/CoreSimulator/&quot;, device_udid)
-                _log.debug('rmtree %s', logs_path)
-                self._filesystem.rmtree(logs_path)
-
-                saved_state_path = self._filesystem.join(self._filesystem.expanduser(&quot;~&quot;), &quot;Library/Saved Application State/&quot;, self.SIMULATOR_BUNDLE_ID + str(i) + &quot;.savedState&quot;)
-                _log.debug('rmtree %s', saved_state_path)
-                self._filesystem.rmtree(saved_state_path)
-
-            except:
-                _log.warning('Unable to remove Simulator' + str(i))
-
-    def setup_environ_for_server(self, server_name=None):
-        _log.debug(&quot;setup_environ_for_server&quot;)
-        env = super(IOSSimulatorPort, self).setup_environ_for_server(server_name)
-        if server_name == self.driver_name():
-            if self.get_option('leaks'):
-                env['MallocStackLogging'] = '1'
-                env['__XPC_MallocStackLogging'] = '1'
-                env['MallocScribble'] = '1'
-                env['__XPC_MallocScribble'] = '1'
-            if self.get_option('guard_malloc'):
-                self._append_value_colon_separated(env, 'DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
-                self._append_value_colon_separated(env, '__XPC_DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
-        env['XML_CATALOG_FILES'] = ''  # work around missing /etc/catalog &lt;rdar://problem/4292995&gt;
-        return env
-
-    def operating_system(self):
-        return 'ios-simulator'
-
-    def check_sys_deps(self, needs_http):
-        if not self.simulator_runtime.available:
-            _log.error('The iOS Simulator runtime with identifier &quot;{0}&quot; cannot be used because it is unavailable.'.format(self.simulator_runtime.identifier))
-            return False
-        return super(IOSSimulatorPort, self).check_sys_deps(needs_http)
-
-    SUBPROCESS_CRASH_REGEX = re.compile('#CRASHED - (?P&lt;subprocess_name&gt;\S+) \(pid (?P&lt;subprocess_pid&gt;\d+)\)')
-
-    def _using_dedicated_simulators(self):
-        return self.get_option('dedicated_simulators')
-
-    def _create_device(self, number):
-        return Simulator.create_device(number, self.simulator_device_type(), self.simulator_runtime)
-
-    def _remove_device(self, number):
-        Simulator.remove_device(number)
-
</del><span class="cx">     def _testing_device(self, number):
</span><del>-        return Simulator.device_number(number)
</del><ins>+        device = self._device_for_worker_number_map()[number]
+        if not device:
+            raise RuntimeError('Device at {} could not be found'.format(number))
+        return device
</ins><span class="cx"> 
</span><span class="cx">     # FIXME: This is only exposed so that SimulatorProcess can use it.
</span><del>-    def device_id_for_worker_number(self, number):
</del><ins>+    def device_for_worker_number(self, number):
</ins><span class="cx">         if self._printing_cmd_line:
</span><del>-            return '&lt;dummy id&gt;'
-        if self._using_dedicated_simulators():
-            return self._testing_device(number).udid
-        return self._current_device.udid
-
-    def get_simulator_path(self, suffix=&quot;&quot;):
-        return os.path.join(self.SIMULATOR_DIRECTORY, &quot;Simulator&quot; + str(suffix) + &quot;.app&quot;)
-
-    def diff_image(self, expected_contents, actual_contents, tolerance=None):
-        if not actual_contents and not expected_contents:
-            return (None, 0, None)
-        if not actual_contents or not expected_contents:
-            return (True, 0, None)
-        if not self._image_differ:
-            self._image_differ = image_diff.IOSSimulatorImageDiffer(self)
-        self.set_option_default('tolerance', 0.1)
-        if tolerance is None:
-            tolerance = self.get_option('tolerance')
-        return self._image_differ.diff_image(expected_contents, actual_contents, tolerance)
-
-    def reset_preferences(self):
-        _log.debug(&quot;reset_preferences&quot;)
-        self._quit_ios_simulator()
-        # Maybe this should delete all devices that we've created?
-
-    def nm_command(self):
-        return self.xcrun_find('nm')
-
-    @property
-    @memoized
-    def developer_dir(self):
-        return self._executive.run_command(['xcode-select', '--print-path']).rstrip()
-
-    def logging_patterns_to_strip(self):
-        return []
-
-    def stderr_patterns_to_strip(self):
-        return []
-
-    def _createSimulatorApps(self):
-        for i in xrange(self.child_processes()):
-            self._createSimulatorApp(i)
-
-    def _createSimulatorApp(self, suffix):
-        destination = self.get_simulator_path(suffix)
-        _log.info(&quot;Creating app:&quot; + destination)
-        if os.path.exists(destination):
-            shutil.rmtree(destination, ignore_errors=True)
-        simulator_app_path = self.developer_dir + &quot;/Applications/Simulator.app&quot;
-        shutil.copytree(simulator_app_path, destination)
-
-        # Update app's package-name inside plist and re-code-sign it
-        plist_path = destination + &quot;/Contents/Info.plist&quot;
-        command = &quot;Set CFBundleIdentifier com.apple.iphonesimulator&quot; + str(suffix)
-        subprocess.check_output([&quot;/usr/libexec/PlistBuddy&quot;, &quot;-c&quot;, command, plist_path])
-        subprocess.check_output([&quot;install_name_tool&quot;, &quot;-add_rpath&quot;, self.developer_dir + &quot;/Library/PrivateFrameworks/&quot;, destination + &quot;/Contents/MacOS/Simulator&quot;])
-        subprocess.check_output([&quot;install_name_tool&quot;, &quot;-add_rpath&quot;, self.developer_dir + &quot;/../Frameworks/&quot;, destination + &quot;/Contents/MacOS/Simulator&quot;])
-        subprocess.check_output([&quot;codesign&quot;, &quot;-fs&quot;, &quot;-&quot;, destination])
-        subprocess.check_output([self.LSREGISTER_PATH, &quot;-f&quot;, destination])
</del><ins>+            return None
+        # When using simulated devices, this means webkitpy is managing the devices.
+        if self.using_multiple_devices():
+            return self._testing_device(number)
+        return self._current_device
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpyportios_devicepy"></a>
<div class="addfile"><h4>Added: trunk/Tools/Scripts/webkitpy/port/ios_device.py (0 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios_device.py                                (rev 0)
+++ trunk/Tools/Scripts/webkitpy/port/ios_device.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+# Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+from webkitpy.port.ios import IOSPort
+
+_log = logging.getLogger(__name__)
+
+
+class IOSDevicePort(IOSPort):
+    port_name = 'ios'
+
+    ARCHITECTURES = ['armv7', 'armv7s', 'arm64']
+    DEFAULT_ARCHITECTURE = 'arm64'
+    VERSION_FALLBACK_ORDER = ['ios-7', 'ios-8', 'ios-9', 'ios-10']
+
+    @classmethod
+    def determine_full_port_name(cls, host, options, port_name):
+        if port_name == cls.port_name:
+            iphoneos_sdk_version = host.platform.xcode_sdk_version('iphoneos')
+            if not iphoneos_sdk_version:
+                raise Exception(&quot;Please install the iOS SDK.&quot;)
+            major_version_number = iphoneos_sdk_version.split('.')[0]
+            port_name = port_name + '-' + major_version_number
+        return port_name
+
+    # Despite their names, these flags do not actually get passed all the way down to webkit-build.
+    def _build_driver_flags(self):
+        return ['--sdk', 'iphoneos'] + (['ARCHS=%s' % self.architecture()] if self.architecture() else [])
+
+    def operating_system(self):
+        return 'ios'
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpyportios_simulatorpyfromrev213235trunkToolsScriptswebkitpyportiospy"></a>
<div class="copfile"><h4>Copied: trunk/Tools/Scripts/webkitpy/port/ios_simulator.py (from rev 213235, trunk/Tools/Scripts/webkitpy/port/ios.py) (0 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios_simulator.py                                (rev 0)
+++ trunk/Tools/Scripts/webkitpy/port/ios_simulator.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -0,0 +1,379 @@
</span><ins>+# Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import os
+import re
+import shutil
+import subprocess
+import time
+
+from webkitpy.common.memoized import memoized
+from webkitpy.layout_tests.models.test_configuration import TestConfiguration
+from webkitpy.port import image_diff
+from webkitpy.port.ios import IOSPort
+from webkitpy.xcode.simulator import Simulator, Runtime, DeviceType
+from webkitpy.common.system.crashlogs import CrashLogs
+
+
+_log = logging.getLogger(__name__)
+
+
+class IOSSimulatorPort(IOSPort):
+    port_name = &quot;ios-simulator&quot;
+
+    FUTURE_VERSION = 'future'
+    ARCHITECTURES = ['x86_64', 'x86']
+    DEFAULT_ARCHITECTURE = 'x86_64'
+
+    DEFAULT_DEVICE_CLASS = 'iphone'
+    CUSTOM_DEVICE_CLASSES = ['ipad', 'iphone7']
+    SDK = 'iphonesimulator'
+
+    SIMULATOR_BUNDLE_ID = 'com.apple.iphonesimulator'
+    SIMULATOR_DIRECTORY = &quot;/tmp/WebKitTestingSimulators/&quot;
+    LSREGISTER_PATH = &quot;/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister&quot;
+    PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE = 100
+
+    DEVICE_CLASS_MAP = {
+        'x86_64': {
+            'iphone': 'iPhone 5s',
+            'iphone7': 'iPhone 7',
+            'ipad': 'iPad Air',
+        },
+        'x86': {
+            'iphone': 'iPhone 5',
+            'ipad': 'iPad Retina',
+        },
+    }
+
+    def __init__(self, host, port_name, **kwargs):
+        super(IOSSimulatorPort, self).__init__(host, port_name, **kwargs)
+
+        optional_device_class = self.get_option('device_class')
+        self._device_class = optional_device_class if optional_device_class else self.DEFAULT_DEVICE_CLASS
+        _log.debug('IOSSimulatorPort _device_class is %s', self._device_class)
+
+        self._current_device = Simulator(host).current_device()
+        if not self._current_device:
+            self.set_option('dedicated_simulators', True)
+        if not self.get_option('dedicated_simulators'):
+            if self.get_option('child_processes') &gt; 1:
+                _log.warn('Cannot have more than one child process when using a running simulator.  Setting child_processes to 1.')
+            self.set_option('child_processes', 1)
+
+    def _device_for_worker_number_map(self):
+        return Simulator.managed_devices
+
+    @property
+    @memoized
+    def simulator_runtime(self):
+        runtime_identifier = self.get_option('runtime')
+        if runtime_identifier:
+            runtime = Runtime.from_identifier(runtime_identifier)
+        else:
+            runtime = Runtime.from_version_string(self.host.platform.xcode_sdk_version('iphonesimulator'))
+        return runtime
+
+    def simulator_device_type(self):
+        device_type_identifier = self.get_option('device_type')
+        if device_type_identifier:
+            _log.debug('simulator_device_type for device identifier %s', device_type_identifier)
+            device_type = DeviceType.from_identifier(device_type_identifier)
+        else:
+            _log.debug('simulator_device_type for device %s', self._device_class)
+            device_name = self.DEVICE_CLASS_MAP[self.architecture()][self._device_class]
+            if not device_name:
+                raise Exception('Failed to find device for architecture {} and device class {}'.format(self.architecture()), self._device_class)
+            device_type = DeviceType.from_name(device_name)
+        return device_type
+
+    @memoized
+    def default_child_processes(self):
+        &quot;&quot;&quot;Return the number of Simulators instances to use for this port.&quot;&quot;&quot;
+        best_child_process_count_for_cpu = self._executive.cpu_count() / 2
+        system_process_count_limit = int(subprocess.check_output([&quot;ulimit&quot;, &quot;-u&quot;]).strip())
+        current_process_count = len(subprocess.check_output([&quot;ps&quot;, &quot;aux&quot;]).strip().split('\n'))
+        _log.debug('Process limit: %d, current #processes: %d' % (system_process_count_limit, current_process_count))
+        maximum_simulator_count_on_this_system = (system_process_count_limit - current_process_count) // self.PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE
+        # FIXME: We should also take into account the available RAM.
+
+        if (maximum_simulator_count_on_this_system &lt; best_child_process_count_for_cpu):
+            _log.warn(&quot;This machine could support %s simulators, but is only configured for %s.&quot;
+                % (best_child_process_count_for_cpu, maximum_simulator_count_on_this_system))
+            _log.warn('Please see &lt;https://trac.webkit.org/wiki/IncreasingKernelLimits&gt;.')
+
+        if maximum_simulator_count_on_this_system == 0:
+            maximum_simulator_count_on_this_system = 1
+
+        return min(maximum_simulator_count_on_this_system, best_child_process_count_for_cpu)
+
+    def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=time.time, sleep_fn=time.sleep, wait_for_log=True):
+        time_fn = time_fn or time.time
+        sleep_fn = sleep_fn or time.sleep
+
+        # FIXME: We should collect the actual crash log for DumpRenderTree.app because it includes more
+        # information (e.g. exception codes) than is available in the stack trace written to standard error.
+        stderr_lines = []
+        crashed_subprocess_name_and_pid = None  # e.g. ('DumpRenderTree.app', 1234)
+        for line in (stderr or '').splitlines():
+            if not crashed_subprocess_name_and_pid:
+                match = self.SUBPROCESS_CRASH_REGEX.match(line)
+                if match:
+                    crashed_subprocess_name_and_pid = (match.group('subprocess_name'), int(match.group('subprocess_pid')))
+                    continue
+            stderr_lines.append(line)
+
+        if crashed_subprocess_name_and_pid:
+            return self._get_crash_log(crashed_subprocess_name_and_pid[0], crashed_subprocess_name_and_pid[1], stdout,
+                '\n'.join(stderr_lines), newer_than, time_fn, sleep_fn, wait_for_log)
+
+        # App crashed
+        _log.debug('looking for crash log for %s:%s' % (name, str(pid)))
+        crash_log = ''
+        crash_logs = CrashLogs(self.host)
+        now = time_fn()
+        deadline = now + 5 * int(self.get_option('child_processes', 1))
+        while not crash_log and now &lt;= deadline:
+            crash_log = crash_logs.find_newest_log(name, pid, include_errors=True, newer_than=newer_than)
+            if not wait_for_log:
+                break
+            if not crash_log or not [line for line in crash_log.splitlines() if not line.startswith('ERROR')]:
+                sleep_fn(0.1)
+                now = time_fn()
+
+        if not crash_log:
+            return stderr, None
+        return stderr, crash_log
+
+    def _build_driver_flags(self):
+        archs = ['ARCHS=i386'] if self.architecture() == 'x86' else []
+        sdk = ['--sdk', 'iphonesimulator']
+        return archs + sdk
+
+    def _generate_all_test_configurations(self):
+        configurations = []
+        for build_type in self.ALL_BUILD_TYPES:
+            for architecture in self.ARCHITECTURES:
+                configurations.append(TestConfiguration(version=self._version, architecture=architecture, build_type=build_type))
+        return configurations
+
+    def default_baseline_search_path(self):
+        if self.get_option('webkit_test_runner'):
+            fallback_names = [self._wk2_port_name()] + [self.port_name] + ['wk2']
+        else:
+            fallback_names = [self.port_name + '-wk1'] + [self.port_name]
+
+        return map(self._webkit_baseline_path, fallback_names)
+
+    def _set_device_class(self, device_class):
+        self._device_class = device_class if device_class else self.DEFAULT_DEVICE_CLASS
+
+    def _create_simulators(self):
+        if (self.default_child_processes() &lt; self.child_processes()):
+            _log.warn('You have specified very high value({0}) for --child-processes'.format(self.child_processes()))
+            _log.warn('maximum child-processes which can be supported on this system are: {0}'.format(self.default_child_processes()))
+            _log.warn('This is very likely to fail.')
+
+        if self._using_dedicated_simulators():
+            self._createSimulatorApps()
+
+            for i in xrange(self.child_processes()):
+                self._create_device(i)
+
+            for i in xrange(self.child_processes()):
+                device_udid = self._testing_device(i).udid
+                Simulator.wait_until_device_is_in_state(device_udid, Simulator.DeviceState.SHUTDOWN)
+                Simulator.reset_device(device_udid)
+        else:
+            assert(self._current_device)
+            if self._current_device.name != self.simulator_device_type().name:
+                _log.warn(&quot;Expected simulator of type '&quot; + self.simulator_device_type().name + &quot;' but found simulator of type '&quot; + self._current_device.name + &quot;'&quot;)
+                _log.warn('The next block of tests may fail due to device mis-match')
+
+    def setup_test_run(self, device_class=None):
+        mac_os_version = self.host.platform.os_version
+
+        self._set_device_class(device_class)
+
+        _log.debug('')
+        _log.debug('setup_test_run for %s', self._device_class)
+
+        self._create_simulators()
+
+        if not self._using_dedicated_simulators():
+            return
+
+        for i in xrange(self.child_processes()):
+            device_udid = self._testing_device(i).udid
+            _log.debug('testing device %s has udid %s', i, device_udid)
+
+            # FIXME: &lt;rdar://problem/20916140&gt; Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
+            self._executive.run_command([
+                'open', '-g', '-b', self.SIMULATOR_BUNDLE_ID + str(i),
+                '--args', '-CurrentDeviceUDID', device_udid])
+
+            if mac_os_version in ['elcapitan', 'yosemite', 'mavericks']:
+                time.sleep(2.5)
+
+        _log.info('Waiting for all iOS Simulators to finish booting.')
+        for i in xrange(self.child_processes()):
+            Simulator.wait_until_device_is_booted(self._testing_device(i).udid)
+
+    def _quit_ios_simulator(self):
+        if not self._using_dedicated_simulators():
+            return
+        _log.debug(&quot;_quit_ios_simulator killing all Simulator processes&quot;)
+        # FIXME: We should kill only the Simulators we started.
+        subprocess.call([&quot;killall&quot;, &quot;-9&quot;, &quot;-m&quot;, &quot;Simulator&quot;])
+
+    def clean_up_test_run(self):
+        super(IOSSimulatorPort, self).clean_up_test_run()
+        _log.debug(&quot;clean_up_test_run&quot;)
+        self._quit_ios_simulator()
+        fifos = [path for path in os.listdir('/tmp') if re.search('org.webkit.(DumpRenderTree|WebKitTestRunner).*_(IN|OUT|ERROR)', path)]
+        for fifo in fifos:
+            try:
+                os.remove(os.path.join('/tmp', fifo))
+            except OSError:
+                _log.warning('Unable to remove ' + fifo)
+                pass
+
+        if not self._using_dedicated_simulators():
+            return
+
+        for i in xrange(self.child_processes()):
+            simulator_path = self.get_simulator_path(i)
+            device_udid = self._testing_device(i).udid
+            self._remove_device(i)
+
+            if not os.path.exists(simulator_path):
+                continue
+            try:
+                self._executive.run_command([self.LSREGISTER_PATH, &quot;-u&quot;, simulator_path])
+
+                _log.debug('rmtree %s', simulator_path)
+                self._filesystem.rmtree(simulator_path)
+
+                logs_path = self._filesystem.join(self._filesystem.expanduser(&quot;~&quot;), &quot;Library/Logs/CoreSimulator/&quot;, device_udid)
+                _log.debug('rmtree %s', logs_path)
+                self._filesystem.rmtree(logs_path)
+
+                saved_state_path = self._filesystem.join(self._filesystem.expanduser(&quot;~&quot;), &quot;Library/Saved Application State/&quot;, self.SIMULATOR_BUNDLE_ID + str(i) + &quot;.savedState&quot;)
+                _log.debug('rmtree %s', saved_state_path)
+                self._filesystem.rmtree(saved_state_path)
+
+            except:
+                _log.warning('Unable to remove Simulator' + str(i))
+
+    def setup_environ_for_server(self, server_name=None):
+        _log.debug(&quot;setup_environ_for_server&quot;)
+        env = super(IOSSimulatorPort, self).setup_environ_for_server(server_name)
+        if server_name == self.driver_name():
+            if self.get_option('leaks'):
+                env['MallocStackLogging'] = '1'
+                env['__XPC_MallocStackLogging'] = '1'
+                env['MallocScribble'] = '1'
+                env['__XPC_MallocScribble'] = '1'
+            if self.get_option('guard_malloc'):
+                self._append_value_colon_separated(env, 'DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
+                self._append_value_colon_separated(env, '__XPC_DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
+        env['XML_CATALOG_FILES'] = ''  # work around missing /etc/catalog &lt;rdar://problem/4292995&gt;
+        return env
+
+    def operating_system(self):
+        return 'ios-simulator'
+
+    def check_sys_deps(self, needs_http):
+        if not self.simulator_runtime.available:
+            _log.error('The iOS Simulator runtime with identifier &quot;{0}&quot; cannot be used because it is unavailable.'.format(self.simulator_runtime.identifier))
+            return False
+        return super(IOSSimulatorPort, self).check_sys_deps(needs_http)
+
+    SUBPROCESS_CRASH_REGEX = re.compile('#CRASHED - (?P&lt;subprocess_name&gt;\S+) \(pid (?P&lt;subprocess_pid&gt;\d+)\)')
+
+    def _using_dedicated_simulators(self):
+        return self.get_option('dedicated_simulators')
+
+    def using_multiple_devices(self):
+        return self._using_dedicated_simulators()
+
+    def _create_device(self, number):
+        return Simulator.create_device(number, self.simulator_device_type(), self.simulator_runtime)
+
+    def _remove_device(self, number):
+        Simulator.remove_device(number)
+
+    def get_simulator_path(self, suffix=&quot;&quot;):
+        return os.path.join(self.SIMULATOR_DIRECTORY, &quot;Simulator&quot; + str(suffix) + &quot;.app&quot;)
+
+    def diff_image(self, expected_contents, actual_contents, tolerance=None):
+        if not actual_contents and not expected_contents:
+            return (None, 0, None)
+        if not actual_contents or not expected_contents:
+            return (True, 0, None)
+        if not self._image_differ:
+            self._image_differ = image_diff.IOSSimulatorImageDiffer(self)
+        self.set_option_default('tolerance', 0.1)
+        if tolerance is None:
+            tolerance = self.get_option('tolerance')
+        return self._image_differ.diff_image(expected_contents, actual_contents, tolerance)
+
+    def reset_preferences(self):
+        _log.debug(&quot;reset_preferences&quot;)
+        self._quit_ios_simulator()
+        # Maybe this should delete all devices that we've created?
+
+    def nm_command(self):
+        return self.xcrun_find('nm')
+
+    @property
+    @memoized
+    def developer_dir(self):
+        return self._executive.run_command(['xcode-select', '--print-path']).rstrip()
+
+    def logging_patterns_to_strip(self):
+        return []
+
+    def stderr_patterns_to_strip(self):
+        return []
+
+    def _createSimulatorApps(self):
+        for i in xrange(self.child_processes()):
+            self._createSimulatorApp(i)
+
+    def _createSimulatorApp(self, suffix):
+        destination = self.get_simulator_path(suffix)
+        _log.info(&quot;Creating app:&quot; + destination)
+        if os.path.exists(destination):
+            shutil.rmtree(destination, ignore_errors=True)
+        simulator_app_path = self.developer_dir + &quot;/Applications/Simulator.app&quot;
+        shutil.copytree(simulator_app_path, destination)
+
+        # Update app's package-name inside plist and re-code-sign it
+        plist_path = destination + &quot;/Contents/Info.plist&quot;
+        command = &quot;Set CFBundleIdentifier com.apple.iphonesimulator&quot; + str(suffix)
+        subprocess.check_output([&quot;/usr/libexec/PlistBuddy&quot;, &quot;-c&quot;, command, plist_path])
+        subprocess.check_output([&quot;install_name_tool&quot;, &quot;-add_rpath&quot;, self.developer_dir + &quot;/Library/PrivateFrameworks/&quot;, destination + &quot;/Contents/MacOS/Simulator&quot;])
+        subprocess.check_output([&quot;install_name_tool&quot;, &quot;-add_rpath&quot;, self.developer_dir + &quot;/../Frameworks/&quot;, destination + &quot;/Contents/MacOS/Simulator&quot;])
+        subprocess.check_output([&quot;codesign&quot;, &quot;-fs&quot;, &quot;-&quot;, destination])
+        subprocess.check_output([self.LSREGISTER_PATH, &quot;-f&quot;, destination])
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpyportios_unittestpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/ios_unittest.py (213235 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios_unittest.py        2017-03-01 19:41:56 UTC (rev 213235)
+++ trunk/Tools/Scripts/webkitpy/port/ios_unittest.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx"> 
</span><span class="cx"> import time
</span><span class="cx"> 
</span><del>-from webkitpy.port.ios import IOSSimulatorPort
</del><ins>+from webkitpy.port.ios_simulator import IOSSimulatorPort
</ins><span class="cx"> from webkitpy.port import darwin_testcase
</span><span class="cx"> from webkitpy.common.system.filesystem_mock import MockFileSystem
</span><span class="cx"> from webkitpy.common.system.outputcapture import OutputCapture
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportsimulator_processpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/simulator_process.py (213235 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/simulator_process.py        2017-03-01 19:41:56 UTC (rev 213235)
+++ trunk/Tools/Scripts/webkitpy/port/simulator_process.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False, worker_number=None):
</span><span class="cx">         self._bundle_id = port_obj.app_identifier_from_bundle(cmd[0])
</span><del>-        self._device = Simulator(port_obj.host).find_device_by_udid(port_obj.device_id_for_worker_number(worker_number))
</del><ins>+        self._device = port_obj.device_for_worker_number(worker_number)
</ins><span class="cx">         if not self._device.install_app(cmd[0], env):
</span><span class="cx">             raise RuntimeError('Failed to install app {} on simulator device {}'.format(cmd[0], self._device.udid))
</span><span class="cx">         env['IPC_IDENTIFIER'] = self._bundle_id + '-' + self._device.udid
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyxcodesimulatorpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/xcode/simulator.py (213235 => 213236)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/xcode/simulator.py        2017-03-01 19:41:56 UTC (rev 213235)
+++ trunk/Tools/Scripts/webkitpy/xcode/simulator.py        2017-03-01 19:47:21 UTC (rev 213236)
</span><span class="lines">@@ -181,7 +181,7 @@
</span><span class="cx">     devices_re = re.compile(
</span><span class="cx">         '\s*(?P&lt;name&gt;.+) \((?P&lt;udid&gt;[^)]+)\) \((?P&lt;state&gt;[^)]+)\)( \((?P&lt;availability&gt;[^)]+)\))?')
</span><span class="cx"> 
</span><del>-    _managed_devices = {}
</del><ins>+    managed_devices = {}
</ins><span class="cx">     Device = None
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, host=None):
</span><span class="lines">@@ -216,21 +216,21 @@
</span><span class="cx">     def create_device(number, device_type, runtime):
</span><span class="cx">         device = Simulator().lookup_or_create_device(device_type.name + ' WebKit Tester' + str(number), device_type, runtime)
</span><span class="cx">         _log.debug('created device {} {}'.format(number, device))
</span><del>-        assert(len(Simulator._managed_devices) == number)
-        Simulator._managed_devices[number] = device
</del><ins>+        assert(len(Simulator.managed_devices) == number)
+        Simulator.managed_devices[number] = device
</ins><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def remove_device(number):
</span><del>-        if not Simulator._managed_devices[number]:
</del><ins>+        if not Simulator.managed_devices[number]:
</ins><span class="cx">             return
</span><del>-        device_udid = Simulator._managed_devices[number].udid
</del><ins>+        device_udid = Simulator.managed_devices[number].udid
</ins><span class="cx">         _log.debug('removing device {} {}'.format(number, device_udid))
</span><del>-        del Simulator._managed_devices[number]
</del><ins>+        del Simulator.managed_devices[number]
</ins><span class="cx">         Simulator.delete_device(device_udid)
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def device_number(number):
</span><del>-        return Simulator._managed_devices[number]
</del><ins>+        return Simulator.managed_devices[number]
</ins><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def device_state_description(state):
</span></span></pre>
</div>
</div>

</body>
</html>