Changeset 193765 in webkit


Ignore:
Timestamp:
Dec 8, 2015 11:49:04 AM (8 years ago)
Author:
commit-queue@webkit.org
Message:

https://bugs.webkit.org/show_bug.cgi?id=151243
<rdar://problem/22955197>

Patch by Aakash Jain <aakash_jain@apple.com> on 2015-12-08
Reviewed by Alexey Proskuryakov.

  • LayoutTestRelay/LayoutTestRelay/main.m:

(getTestingSimDevice): Use separate testing device for each worker.

  • Scripts/webkitpy/layout_tests/controllers/manager.py:

(Manager.run): Perform cleanup even if setup fails.

  • Scripts/webkitpy/port/ios.py:

(IOSSimulatorPort.default_child_processes): Calculate number of simulators to use.
(IOSSimulatorPort.child_processes): Gets the number of simulators from options variable.
(IOSSimulatorPort.setup_test_run): Handle mulitple simulators.
(IOSSimulatorPort._quit_ios_simulator): Same
(IOSSimulatorPort.clean_up_test_run): Same
(IOSSimulatorPort.check_sys_deps): Same
(IOSSimulatorPort.testing_device): Same
(IOSSimulatorPort.reset_preferences): Same
(IOSSimulatorPort.get_simulator_path): Return simulator path.
(IOSSimulatorPort._createSimulatorApp): Create the copy of simulator app.

  • Scripts/webkitpy/xcode/simulator.py:

(Device.delete): Delete the simulator device.
(Simulator.delete_device): Same
(Simulator.wait_until_device_is_booted): Wait for device booting.

Location:
trunk/Tools
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r193744 r193765  
     12015-12-08  Aakash Jain  <aakash_jain@apple.com>
     2
     3        https://bugs.webkit.org/show_bug.cgi?id=151243
     4        <rdar://problem/22955197>
     5
     6        Reviewed by Alexey Proskuryakov.
     7
     8        * LayoutTestRelay/LayoutTestRelay/main.m:
     9        (getTestingSimDevice): Use separate testing device for each worker.
     10        * Scripts/webkitpy/layout_tests/controllers/manager.py:
     11        (Manager.run): Perform cleanup even if setup fails.
     12        * Scripts/webkitpy/port/ios.py:
     13        (IOSSimulatorPort.default_child_processes): Calculate number of simulators to use.
     14        (IOSSimulatorPort.child_processes): Gets the number of simulators from options variable.
     15        (IOSSimulatorPort.setup_test_run): Handle mulitple simulators.
     16        (IOSSimulatorPort._quit_ios_simulator): Same
     17        (IOSSimulatorPort.clean_up_test_run): Same
     18        (IOSSimulatorPort.check_sys_deps): Same
     19        (IOSSimulatorPort.testing_device): Same
     20        (IOSSimulatorPort.reset_preferences): Same
     21        (IOSSimulatorPort.get_simulator_path): Return simulator path.
     22        (IOSSimulatorPort._createSimulatorApp): Create the copy of simulator app.
     23        * Scripts/webkitpy/xcode/simulator.py:
     24        (Device.delete): Delete the simulator device.
     25        (Simulator.delete_device): Same
     26        (Simulator.wait_until_device_is_booted): Wait for device booting.
     27
    1282015-12-08  Ryuan Choi  <ryuan.choi@navercorp.com>
    229
  • trunk/Tools/LayoutTestRelay/LayoutTestRelay/main.m

    r185478 r193765  
    4444}
    4545
    46 SimDevice *getTestingSimDevice(SimDeviceType *deviceType, SimRuntime *runtime)
     46SimDevice *getTestingSimDevice(SimDeviceType *deviceType, SimRuntime *runtime, NSString *suffix)
    4747{
    4848    NSString *deviceName = [[[[deviceType identifier] componentsSeparatedByString:@"."] lastObject] stringByReplacingOccurrencesOfString:@"-" withString:@" "];
    49     deviceName = [deviceName stringByAppendingString:@" WebKit Tester"];
     49    deviceName = [NSString stringWithFormat:@"%@%@%@", deviceName, @" WebKit Tester", suffix];
    5050
    5151    for (SimDevice *device in [[SimDeviceSet defaultSet] devices]) {
     
    137137        NSArray *dumpToolArguments = getDumpToolArguments();
    138138
    139         SimDevice *device = getTestingSimDevice(deviceType, runtime);
     139        SimDevice *device = getTestingSimDevice(deviceType, runtime, suffix);
    140140
    141141        relayController = [[LTRelayController alloc] initWithDevice:device productDir:productDir appPath:appPath identifierSuffix:suffix dumpToolArguments:dumpToolArguments];
  • trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py

    r191374 r193765  
    188188            return test_run_results.RunDetails(exit_code=-1)
    189189
    190         if not self._set_up_run(tests_to_run):
    191             return test_run_results.RunDetails(exit_code=-1)
    192 
    193         enabled_pixel_tests_in_retry = False
    194190        try:
     191            if not self._set_up_run(tests_to_run):
     192                return test_run_results.RunDetails(exit_code=-1)
     193
     194            enabled_pixel_tests_in_retry = False
    195195            initial_results = self._run_tests(tests_to_run, tests_to_skip, self._options.repeat_each, self._options.iterations,
    196196                int(self._options.child_processes), retrying=False)
  • trunk/Tools/Scripts/webkitpy/port/ios.py

    r192127 r193765  
    7171class IOSSimulatorPort(Port):
    7272    port_name = "ios-simulator"
    73 
    7473    FUTURE_VERSION = 'future'
    75 
    7674    ARCHITECTURES = ['x86_64', 'x86']
    77 
    7875    DEFAULT_ARCHITECTURE = 'x86_64'
    79 
    8076    SIMULATOR_BUNDLE_ID = 'com.apple.iphonesimulator'
    81 
    8277    relay_name = 'LayoutTestRelay'
     78    SIMULATOR_DIRECTORY = "/tmp/WebKitTestingSimulators/"
     79    LSREGISTER_PATH = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister"
     80    PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE = 100
    8381
    8482    def __init__(self, *args, **kwargs):
     
    131129        return self._filesystem.join(path, self.relay_name)
    132130
     131    @memoized
     132    def child_processes(self):
     133        return int(self.get_option('child_processes'))
     134
     135    @memoized
     136    def default_child_processes(self):
     137        """Return the number of Simulators instances to use for this port."""
     138        best_child_process_count_for_cpu = self._executive.cpu_count() / 2
     139        system_process_count_limit = int(subprocess.check_output(["launchctl", "limit", "maxproc"]).strip().split()[1])
     140        current_process_count = len(subprocess.check_output(["ps", "aux"]).strip().split('\n'))
     141        _log.info('Process limit: %d, current #processes: %d' % (system_process_count_limit, current_process_count))
     142        maximum_simulator_count_on_this_system = (system_process_count_limit - current_process_count) // self.PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE
     143        # FIXME: We should also take into account the available RAM.
     144
     145        if (maximum_simulator_count_on_this_system < best_child_process_count_for_cpu):
     146            _log.warn("This machine could support %s child processes, but only has enough process limit for %s."
     147                % (best_child_process_count_for_cpu, maximum_simulator_count_on_this_system))
     148            _log.warn('Run "launchctl limit" to check these limits')
     149            # FIXME: Add url for webpage explaining how to increase these limits.
     150
     151        return min(maximum_simulator_count_on_this_system, best_child_process_count_for_cpu)
     152
    133153    def default_timeout_ms(self):
    134154        if self.get_option('guard_malloc'):
     
    201221
    202222    def setup_test_run(self):
    203         device_udid = self.testing_device.udid
    204         # FIXME: <rdar://problem/20916140> Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
    205         self._executive.run_command([
    206             'open', '-b', self.SIMULATOR_BUNDLE_ID,
    207             '--args', '-CurrentDeviceUDID', device_udid])
    208         Simulator.wait_until_device_is_in_state(device_udid, Simulator.DeviceState.BOOTED)
    209 
    210         # FIXME: Pause here until SpringBoard finishes launching to workaround <rdar://problem/20000383>.
    211         boot_delay = 30
    212         _log.debug('Waiting {seconds} seconds for iOS Simulator to finish booting ...'.format(seconds=boot_delay))
    213         time.sleep(boot_delay)
     223        mac_os_version = self.host.platform.os_version
     224        for i in xrange(self.child_processes()):
     225            device_udid = self.testing_device(i).udid
     226            # FIXME: <rdar://problem/20916140> Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
     227            self._executive.run_command([
     228                'open', '-b', self.SIMULATOR_BUNDLE_ID + str(i),
     229                '--args', '-CurrentDeviceUDID', device_udid])
     230
     231            if mac_os_version in ['elcapitan', 'yosemite', 'mavericks']:
     232                time.sleep(1)
     233
     234        _log.info('Waiting for all iOS Simulators to finish booting.')
     235        for i in xrange(self.child_processes()):
     236            Simulator.wait_until_device_is_booted(self.testing_device(i).udid)
    214237
    215238    def _quit_ios_simulator(self):
    216         # FIXME: <rdar://problem/20916140> Switch to using CoreSimulator.framework for launching and quitting iOS Simulator
    217         self._executive.run_command(['osascript', '-e', 'tell application id "{0}" to quit'.format(self.SIMULATOR_BUNDLE_ID)])
     239        # FIXME: We should kill only the Simulators we started.
     240        subprocess.call(["killall", "-9", "-v", "-m", "Simulator"])
    218241
    219242    def clean_up_test_run(self):
     
    228251                pass
    229252
     253        for i in xrange(self.child_processes()):
     254            try:
     255                subprocess.call([self.LSREGISTER_PATH, "-v", "-u", self.get_simulator_path(i)])
     256                shutil.rmtree(self.get_simulator_path(i), ignore_errors=True)
     257                Simulator().delete_device(self.testing_device(i).udid)
     258            except:
     259                _log.warning('Unable to remove Simulator' + str(i))
     260
    230261    def setup_environ_for_server(self, server_name=None):
    231262        env = super(IOSSimulatorPort, self).setup_environ_for_server(server_name)
     
    246277            _log.error('The iOS Simulator runtime with identifier "{0}" cannot be used because it is unavailable.'.format(self.simulator_runtime.identifier))
    247278            return False
    248         testing_device = self.testing_device  # May create a new simulator device
    249 
    250         if not Simulator.check_simulator_device_and_erase_if_needed(self.host, testing_device.udid):
    251             _log.error('Unable to boot the simulator device with UDID {0}.'.format(testing_device.udid))
    252             return False
     279        for i in xrange(self.child_processes()):
     280            # FIXME: This creates the devices sequentially, doing this in parallel can improve performance.
     281            testing_device = self.testing_device(i)
     282            _log.debug('Verifying Simulator{0} with UDID {1}.'.format(i, testing_device.udid))
     283
     284            # FIXME: This is very slow, especially for mulitple simulators, we probably do not need
     285            # this checking as we are re-creating new simulator apps and devices in every run.
     286            if not Simulator.check_simulator_device_and_erase_if_needed(self.host, testing_device.udid):
     287                _log.error('Unable to boot the simulator device with UDID {0}.'.format(testing_device.udid))
     288                return False
    253289        return super(IOSSimulatorPort, self).check_sys_deps(needs_http)
    254290
     
    324360        return stderr, crash_log
    325361
    326     @property
    327     @memoized
    328     def testing_device(self):
    329         return Simulator().lookup_or_create_device(self.simulator_device_type.name + ' WebKit Tester', self.simulator_device_type, self.simulator_runtime)
     362    @memoized
     363    def testing_device(self, number):
     364        return Simulator().lookup_or_create_device(self.simulator_device_type.name + ' WebKit Tester' + str(number), self.simulator_device_type, self.simulator_runtime)
     365
     366    def get_simulator_path(self, suffix=""):
     367        return os.path.join(self.SIMULATOR_DIRECTORY, "Simulator" + str(suffix) + ".app")
    330368
    331369    def _merge_crash_logs(self, logs, new_logs, crashed_processes):
     
    397435
    398436    def reset_preferences(self):
    399         # We assume that if testing_device is booted that it was booted by the iOS Simulator app
    400         # (as opposed to simctl). So, quit the iOS Simulator app to shutdown testing_device.
     437        if (self.default_child_processes() < self.child_processes()):
     438                _log.warn("You have specified very high value({0}) for --child-processes".format(self.child_processes()))
     439                _log.warn("maximum child-processes which can be supported on this system are: {0}".format(self.default_child_processes()))
     440                _log.warn("This is very likely to fail.")
     441
    401442        self._quit_ios_simulator()
    402         Simulator.wait_until_device_is_in_state(self.testing_device.udid, Simulator.DeviceState.SHUTDOWN)
    403 
    404         data_path = os.path.join(self.testing_device.path, 'data')
    405         if os.path.isdir(data_path):
    406             shutil.rmtree(data_path)
     443        self._createSimulatorApps()
     444
     445        for i in xrange(self.child_processes()):
     446            Simulator.wait_until_device_is_in_state(self.testing_device(i).udid, Simulator.DeviceState.SHUTDOWN)
     447
     448            data_path = os.path.join(self.testing_device(i).path, 'data')
     449            if os.path.isdir(data_path):
     450                shutil.rmtree(data_path)
    407451
    408452    def make_command(self):
     
    429473    def stderr_patterns_to_strip(self):
    430474        return []
     475
     476    def _createSimulatorApps(self):
     477        for i in xrange(self.child_processes()):
     478            self._createSimulatorApp(i)
     479
     480    def _createSimulatorApp(self, suffix):
     481        destination = self.get_simulator_path(suffix)
     482        _log.info("Creating app:" + destination)
     483        if os.path.exists(destination):
     484            shutil.rmtree(destination, ignore_errors=True)
     485        simulator_app_path = self.developer_dir + "/Applications/Simulator.app"
     486        shutil.copytree(simulator_app_path, destination)
     487
     488        # Update app's package-name inside plist and re-code-sign it
     489        plist_path = destination + "/Contents/Info.plist"
     490        command = "Set CFBundleIdentifier com.apple.iphonesimulator" + str(suffix)
     491        subprocess.check_output(["/usr/libexec/PlistBuddy", "-c", command, plist_path])
     492        subprocess.check_output(["install_name_tool", "-add_rpath", self.developer_dir + "/Library/PrivateFrameworks/", destination + "/Contents/MacOS/Simulator"])
     493        subprocess.check_output(["codesign", "-fs", "-", destination])
     494        subprocess.check_output([self.LSREGISTER_PATH, "-v", "-f", destination])
  • trunk/Tools/Scripts/webkitpy/xcode/simulator.py

    r189573 r193765  
    216216        return Simulator().find_device_by_udid(device_udid)
    217217
     218    @classmethod
     219    def delete(cls, udid):
     220        """
     221        Delete the given CoreSimulator device.
     222        :param udid: The udid of the device.
     223        :type udid: str
     224        """
     225        subprocess.call(['xcrun', 'simctl', 'delete', udid])
     226
    218227    def __eq__(self, other):
    219228        return self.udid == other.udid
     
    266275
    267276    @staticmethod
     277    def wait_until_device_is_booted(udid, timeout_seconds=60 * 5):
     278        with timeout(seconds=timeout_seconds):
     279            while True:
     280                state = subprocess.check_output(['xcrun', 'simctl', 'spawn', udid, 'launchctl', 'print', 'system']).strip()
     281                if re.search("A[\s]+com.apple.springboard.services", state):
     282                    return
     283                time.sleep(1)
     284
     285    @staticmethod
    268286    def wait_until_device_is_in_state(udid, wait_until_state, timeout_seconds=60 * 5):
    269287        with timeout(seconds=timeout_seconds):
     
    299317            return Simulator._boot_and_shutdown_simulator_device(host, udid) == 0  # Can boot device
    300318        return False  # Cannot boot or erase device
     319
     320    def delete_device(self, udid):
     321        Device.delete(udid)
    301322
    302323    def refresh(self):
Note: See TracChangeset for help on using the changeset viewer.