Skip to content

[API Tests] Reduce run-api-tests startup overhead when running specific tests#60911

Merged
webkit-commit-queue merged 1 commit intoWebKit:mainfrom
rr-codes:eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests
Mar 20, 2026
Merged

[API Tests] Reduce run-api-tests startup overhead when running specific tests#60911
webkit-commit-queue merged 1 commit intoWebKit:mainfrom
rr-codes:eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests

Conversation

@rr-codes
Copy link
Copy Markdown
Contributor

@rr-codes rr-codes commented Mar 19, 2026

a80da14

[API Tests] Reduce run-api-tests startup overhead when running specific tests
https://bugs.webkit.org/show_bug.cgi?id=310247
rdar://172887928

Reviewed by Jonathan Bedard.

This patch reduces the startup overhead of run-api-tests by addressing
several bottlenecks in the Python script's initialization path.

1. Defer default_configuration() in configuration_options() (~500ms)

The -t/--target option eagerly created a Config object and called
default_configuration(), which spawns a Perl subprocess
(webkit-build-directory) to determine the build directory. This
happened unconditionally at option-parse time, even when --debug or
--release was explicitly passed. Changed the default to None; the
port base class (base.py:168-169) already has a lazy fallback that
calls default_configuration() only when no configuration was set.

2. Make SDK resolution lazy in embedded port modules (~1-1.5s)

Six embedded port modules (ios_simulator, ios_device,
watch_simulator, watch_device, visionos_simulator, visionos_device)
called apple_additions().get_sdk() at class-definition time, which
triggered xcodebuild -showsdks (~1s+) the moment any of these
modules was imported by PortFactory.get(). Fixed by converting SDK
from a class-level attribute to a lazy @property that defers the
lookup until first access. Each class now has a _DEFAULT_SDK class
attribute for the base SDK name and a @property SDK that calls
apple_additions().get_sdk() only when needed. This aligns with the
EmbeddedPort base class, which already declares SDK as
@property @abstractmethod. Also updated EmbeddedDevicePort's
determine_full_port_name() classmethod to use cls._DEFAULT_SDK
instead of cls.SDK, since properties don't work on class references.
Additionally, PORT_CLASSES is restored to alphabetical order and
the import logic is extracted into a _load_port_class() helper.

3. Defer configuration_for_upload until needed (~100-200ms)

configuration_for_upload was computed unconditionally before test
collection, but is only needed when --report-urls is specified.
Moved it into the upload block.

4. Skip test collection when exact test names are provided.

Previously, `_collect_tests` always copied the test binary to "ToBeListed" and
spawned it with --gtest_list_tests to enumerate every available test, even when
the user specified exact test names on the command line (~0.5-1s of overhead).

Fix by adding `_try_collect_exact_tests`, which detects when all arguments are
fully-qualified test names (no glob wildcards) and resolves them directly
without listing. For the `<Binary>.<Suite>.<Test>` form, the name is used as-is.
For the `<Suite>.<Test>` form, the appropriate binary prefix is added. The method
falls back to the full listing path for glob patterns, partial matches like
`<Binary>.<Suite>`, or when no arguments are given.

5. Remove unnecessary preference reset from API test runs.

`_set_up_run` unconditionally called `reset_preferences()`, which runs two
sequential `defaults delete` commands for the DumpRenderTree and
WebKitTestRunner preference domains (~0.1s). These are layout test runner
preference domains and are not used by the API test binaries.

6. Skip build check when --no-build is set.

`check_api_test_build` was called unconditionally, resolving binary paths and
checking filesystem existence even when --no-build (the default) was passed.
Now the entire build check is skipped when build=False, deferring the first
build-directory resolution to `_collect_tests` where it's actually needed.

7. Lazy-import webkitscmpy in port/base.py (~150-200ms)

`from webkitscmpy import local` was a module-level import that loaded the
entire webkitscmpy dependency graph (registering dozens of AutoInstall
packages) on every run. Moved it into `commits_for_upload()`, the only
method that uses it.

8. Cache path_to_api_test_binaries() in check_api_test_build.

`check_api_test_build` called `path_to_api_test_binaries()` twice: once to
get the key list and once to iterate. Stored the result in a local variable
to avoid the redundant dict reconstruction.

9. Lazy-import Upload and remove dead imports in manager.py.

Moved `from webkitpy.results.upload import Upload` into the upload codepath
where it's actually used. Removed completely unused `DeviceRequest` and
`SimulatedDeviceManager` imports.

* Tools/Scripts/webkitpy/api_tests/manager.py:
(Manager):
(Manager._is_exact_test_name):
(Manager._try_collect_exact_tests):
(Manager._collect_tests):
(Manager._set_up_run):
(Manager.run):
* Tools/Scripts/webkitpy/api_tests/manager_unittest.py:
(test_is_exact_test_name):
* Tools/Scripts/webkitpy/port/base.py:
(Port.check_api_test_build):
(Port.commits_for_upload):
* Tools/Scripts/webkitpy/port/embedded_device.py:
(EmbeddedDevicePort.determine_full_port_name):
* Tools/Scripts/webkitpy/port/factory.py:
(configuration_options):
(PortFactory):
(PortFactory._load_port_class):
(PortFactory.get):
(PortFactory.get.in):
* Tools/Scripts/webkitpy/port/ios_device.py:
(IOSDevicePort):
(IOSDevicePort.SDK):
* Tools/Scripts/webkitpy/port/ios_simulator.py:
(IOSSimulatorPort):
(IOSSimulatorPort.SDK):
* Tools/Scripts/webkitpy/port/port_testcase.py:
(bind_mock_apple_additions.MockAppleAdditions):
(bind_mock_apple_additions.MockAppleAdditions.get_sdk):
* Tools/Scripts/webkitpy/port/visionos_device.py:
(VisionOSDevicePort):
(VisionOSDevicePort.SDK):
* Tools/Scripts/webkitpy/port/visionos_simulator.py:
(VisionOSSimulatorPort):
(VisionOSSimulatorPort.SDK):
* Tools/Scripts/webkitpy/port/watch_device.py:
(WatchDevicePort):
(WatchDevicePort.SDK):
* Tools/Scripts/webkitpy/port/watch_simulator.py:
(WatchSimulatorPort):
(WatchSimulatorPort.SDK):

Canonical link: https://commits.webkit.org/309636@main

6e1cfbb

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe 🛠 win ⏳ 🛠 ios-apple
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 🧪 win-tests loading 🛠 mac-apple
✅ 🧪 webkitperl 🧪 ios-wk2 🧪 api-mac ✅ 🧪 api-wpe ✅ 🛠 vision-apple
✅ 🧪 webkitpy 🧪 ios-wk2-wpt 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
🧪 api-ios 🧪 mac-wk1 ✅ 🛠 gtk
🧪 mac-wk2 🧪 gtk-wk2
✅ 🛠 vision 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
🛠 🧪 merge ✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🛠 🧪 unsafe-merge ✅ 🧪 vision-wk2 🧪 mac-intel-wk2
✅ 🛠 tv
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@rr-codes rr-codes self-assigned this Mar 19, 2026
@rr-codes rr-codes added the WebKit Misc. For miscellaneous bugs in the WebKit framework (and not JavaScriptCore or WebCore). label Mar 19, 2026
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from b9a3d91 to e244c7f Compare March 19, 2026 04:16
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from e244c7f to 3b39240 Compare March 19, 2026 05:03
Copy link
Copy Markdown
Member

@gsnedders gsnedders left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @JonWBedard, and probably @Smackteo, should have a look at the API tests changes.

@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 3b39240 to 82a27e8 Compare March 19, 2026 20:58
@rr-codes rr-codes changed the title [API Tests] Reduce run-api-tests startup overhead when running specific tests [API Tests] Reduce run-api-tests startup overhead when running specific tests https://bugs.webkit.org/show_bug.cgi?id=310247 rdar://172887928 Mar 19, 2026
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 82a27e8 to 39ffd79 Compare March 19, 2026 21:42
@rr-codes rr-codes changed the title [API Tests] Reduce run-api-tests startup overhead when running specific tests https://bugs.webkit.org/show_bug.cgi?id=310247 rdar://172887928 [API Tests] Reduce run-api-tests startup overhead when running specific tests Mar 19, 2026
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 39ffd79 to 21e9eff Compare March 19, 2026 21:59
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 21e9eff to 5a1eba7 Compare March 19, 2026 23:22
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 5a1eba7 to eac26fd Compare March 20, 2026 04:01
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from eac26fd to 9120ab2 Compare March 20, 2026 06:33
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Mar 20, 2026
@rr-codes rr-codes removed the merging-blocked Applied to prevent a change from being merged label Mar 20, 2026
@rr-codes rr-codes added the merge-queue Applied to send a pull request to merge-queue label Mar 20, 2026
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

No reviewer information in commit message, blocking PR #60911. Details: Build #33902

@webkit-commit-queue webkit-commit-queue added merging-blocked Applied to prevent a change from being merged and removed merge-queue Applied to send a pull request to merge-queue labels Mar 20, 2026
@rr-codes rr-codes removed the merging-blocked Applied to prevent a change from being merged label Mar 20, 2026
@rr-codes rr-codes force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 9120ab2 to 6e1cfbb Compare March 20, 2026 20:49
@rr-codes rr-codes added merge-queue Applied to send a pull request to merge-queue unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing and removed merge-queue Applied to send a pull request to merge-queue labels Mar 20, 2026
@webkit-commit-queue webkit-commit-queue force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 6e1cfbb to 6097dd8 Compare March 20, 2026 21:41
…ic tests

https://bugs.webkit.org/show_bug.cgi?id=310247
rdar://172887928

Reviewed by Jonathan Bedard.

This patch reduces the startup overhead of run-api-tests by addressing
several bottlenecks in the Python script's initialization path.

1. Defer default_configuration() in configuration_options() (~500ms)

The -t/--target option eagerly created a Config object and called
default_configuration(), which spawns a Perl subprocess
(webkit-build-directory) to determine the build directory. This
happened unconditionally at option-parse time, even when --debug or
--release was explicitly passed. Changed the default to None; the
port base class (base.py:168-169) already has a lazy fallback that
calls default_configuration() only when no configuration was set.

2. Make SDK resolution lazy in embedded port modules (~1-1.5s)

Six embedded port modules (ios_simulator, ios_device,
watch_simulator, watch_device, visionos_simulator, visionos_device)
called apple_additions().get_sdk() at class-definition time, which
triggered xcodebuild -showsdks (~1s+) the moment any of these
modules was imported by PortFactory.get(). Fixed by converting SDK
from a class-level attribute to a lazy @Property that defers the
lookup until first access. Each class now has a _DEFAULT_SDK class
attribute for the base SDK name and a @Property SDK that calls
apple_additions().get_sdk() only when needed. This aligns with the
EmbeddedPort base class, which already declares SDK as
@Property @AbstractMethod. Also updated EmbeddedDevicePort's
determine_full_port_name() classmethod to use cls._DEFAULT_SDK
instead of cls.SDK, since properties don't work on class references.
Additionally, PORT_CLASSES is restored to alphabetical order and
the import logic is extracted into a _load_port_class() helper.

3. Defer configuration_for_upload until needed (~100-200ms)

configuration_for_upload was computed unconditionally before test
collection, but is only needed when --report-urls is specified.
Moved it into the upload block.

4. Skip test collection when exact test names are provided.

Previously, `_collect_tests` always copied the test binary to "ToBeListed" and
spawned it with --gtest_list_tests to enumerate every available test, even when
the user specified exact test names on the command line (~0.5-1s of overhead).

Fix by adding `_try_collect_exact_tests`, which detects when all arguments are
fully-qualified test names (no glob wildcards) and resolves them directly
without listing. For the `<Binary>.<Suite>.<Test>` form, the name is used as-is.
For the `<Suite>.<Test>` form, the appropriate binary prefix is added. The method
falls back to the full listing path for glob patterns, partial matches like
`<Binary>.<Suite>`, or when no arguments are given.

5. Remove unnecessary preference reset from API test runs.

`_set_up_run` unconditionally called `reset_preferences()`, which runs two
sequential `defaults delete` commands for the DumpRenderTree and
WebKitTestRunner preference domains (~0.1s). These are layout test runner
preference domains and are not used by the API test binaries.

6. Skip build check when --no-build is set.

`check_api_test_build` was called unconditionally, resolving binary paths and
checking filesystem existence even when --no-build (the default) was passed.
Now the entire build check is skipped when build=False, deferring the first
build-directory resolution to `_collect_tests` where it's actually needed.

7. Lazy-import webkitscmpy in port/base.py (~150-200ms)

`from webkitscmpy import local` was a module-level import that loaded the
entire webkitscmpy dependency graph (registering dozens of AutoInstall
packages) on every run. Moved it into `commits_for_upload()`, the only
method that uses it.

8. Cache path_to_api_test_binaries() in check_api_test_build.

`check_api_test_build` called `path_to_api_test_binaries()` twice: once to
get the key list and once to iterate. Stored the result in a local variable
to avoid the redundant dict reconstruction.

9. Lazy-import Upload and remove dead imports in manager.py.

Moved `from webkitpy.results.upload import Upload` into the upload codepath
where it's actually used. Removed completely unused `DeviceRequest` and
`SimulatedDeviceManager` imports.

* Tools/Scripts/webkitpy/api_tests/manager.py:
(Manager):
(Manager._is_exact_test_name):
(Manager._try_collect_exact_tests):
(Manager._collect_tests):
(Manager._set_up_run):
(Manager.run):
* Tools/Scripts/webkitpy/api_tests/manager_unittest.py:
(test_is_exact_test_name):
* Tools/Scripts/webkitpy/port/base.py:
(Port.check_api_test_build):
(Port.commits_for_upload):
* Tools/Scripts/webkitpy/port/embedded_device.py:
(EmbeddedDevicePort.determine_full_port_name):
* Tools/Scripts/webkitpy/port/factory.py:
(configuration_options):
(PortFactory):
(PortFactory._load_port_class):
(PortFactory.get):
(PortFactory.get.in):
* Tools/Scripts/webkitpy/port/ios_device.py:
(IOSDevicePort):
(IOSDevicePort.SDK):
* Tools/Scripts/webkitpy/port/ios_simulator.py:
(IOSSimulatorPort):
(IOSSimulatorPort.SDK):
* Tools/Scripts/webkitpy/port/port_testcase.py:
(bind_mock_apple_additions.MockAppleAdditions):
(bind_mock_apple_additions.MockAppleAdditions.get_sdk):
* Tools/Scripts/webkitpy/port/visionos_device.py:
(VisionOSDevicePort):
(VisionOSDevicePort.SDK):
* Tools/Scripts/webkitpy/port/visionos_simulator.py:
(VisionOSSimulatorPort):
(VisionOSSimulatorPort.SDK):
* Tools/Scripts/webkitpy/port/watch_device.py:
(WatchDevicePort):
(WatchDevicePort.SDK):
* Tools/Scripts/webkitpy/port/watch_simulator.py:
(WatchSimulatorPort):
(WatchSimulatorPort.SDK):

Canonical link: https://commits.webkit.org/309636@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/API-Tests-Reduce-run-api-tests-startup-overhead-when-running-specific-tests branch from 6097dd8 to a80da14 Compare March 20, 2026 21:43
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 309636@main (a80da14): https://commits.webkit.org/309636@main

Reviewed commits have been landed. Closing PR #60911 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit a80da14 into WebKit:main Mar 20, 2026
@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WebKit Misc. For miscellaneous bugs in the WebKit framework (and not JavaScriptCore or WebCore).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants