Skip to content

Avoid duplicate ops registration in macOS executor_runner#19804

Merged
digantdesai merged 2 commits into
pytorch:mainfrom
devin-lai:fix-coreml-duplicate-ops-registration
Jun 2, 2026
Merged

Avoid duplicate ops registration in macOS executor_runner#19804
digantdesai merged 2 commits into
pytorch:mainfrom
devin-lai:fix-coreml-duplicate-ops-registration

Conversation

@devin-lai

@devin-lai devin-lai commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

The macOS preset builds executor_runner with optimized kernels enabled, so the top-level runner link logic already selects optimized_native_cpu_ops_lib as the ops registration library.

coremldelegate was also linking portable_ops_lib and portable_kernels through EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER. Since coremldelegate is included through executorch_backends, executor_runner could force-load both portable_ops_lib and optimized_native_cpu_ops_lib. Their generated static initializers register overlapping ATen kernels, causing executor_runner to abort before main() with a duplicate registration error.

This removes the CoreML-side ops-lib link and removes the obsolete EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER preset option. The CoreML executor runner under examples/apple/coreml/executor_runner is not a CMake target, so this option was not actually building that runner.

Compatibility

The coreml_executor_runner built by examples/apple/coreml/scripts/build_executor_runner.sh is unaffected. That script builds the relevant CMake targets, then stages libportable_ops_lib.a and libportable_kernels.a into examples/apple/coreml/executor_runner/libraries/. The Xcode project links those archives directly, independent of libcoremldelegate.a's internal link list, so the Xcode-built runner keeps working through its own link line.

Other CMake consumers of coremldelegate already select an ops registration library independently before force-loading coremldelegate, so they are unaffected by removing the private portable-kernel link from the delegate. Non-Apple platforms do not build coremldelegate because backends/apple/coreml/CMakeLists.txt is gated by if(APPLE). The iOS and iOS-simulator presets never set the removed option.

Test plan

cmake --preset macos
cmake --build cmake-out --target executor_runner --config Debug -j
./cmake-out/Debug/executor_runner
cmake --build cmake-out --target coremldelegate --config Debug -j

Verified the executor_runner link line no longer contains libportable_ops_lib.a or unprefixed libportable_kernels.a. liboptimized_native_cpu_ops_lib.a is still force-loaded. liboptimized_portable_kernels.a is still present, which is expected because it is one of optimized_native_cpu_ops_lib's kernel libraries.

Running without --model_path now reaches main(), resets the threadpool, and fails only on the expected missing model.pte path instead of aborting during static kernel registration.

Authored with Claude.

cc @larryliu0820 @GregoryComer @kimishpatel @YifanShenSZ @cymbalrush @metascroy

The macOS preset enables both EXECUTORCH_BUILD_KERNELS_OPTIMIZED and
EXECUTORCH_BUILD_EXECUTOR_RUNNER, so the top-level CMake selects
optimized_native_cpu_ops_lib as the runner's ops registration library.
coremldelegate is pulled into the runner's link line through
executorch_backends and force-loaded, and it was also privately linking
portable_ops_lib and portable_kernels whenever
EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER was on. The runner therefore ended
up with optimized_native_cpu_ops_lib and portable_ops_lib both registering
overlapping ATen kernels at static-init time, aborting before main().

Drop the misplaced portable-kernel link from coremldelegate and remove the
now-unused EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER option. The option never
gated building a real CMake runner target; the CoreML executor runner under
examples/apple/coreml/executor_runner is an Xcode project, and the
build_executor_runner.sh script that drives it stages libportable_ops_lib.a
and libportable_kernels.a into examples/apple/coreml/executor_runner/libraries/
where the Xcode project links them directly, independent of
libcoremldelegate.a's link list.
@pytorch-bot

pytorch-bot Bot commented May 27, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/19804

Note: Links to docs will display an error until the docs builds have been completed.

❌ 1 Awaiting Approval, 1 New Failure, 1 Pending, 1 Unrelated Failure, 1 Unclassified Failure

As of commit ff0ba0d with merge base a89a05a (image):

AWAITING APPROVAL - The following workflow needs approval before CI can run:

NEW FAILURE - The following job has failed:

UNCLASSIFIED FAILURE - DrCI could not classify the following job because the workflow did not run on the merge base. The failure may be pre-existing on trunk or introduced by this PR:

  • trunk / test-coreml-delegate / macos-job (gh) (this job did not run on the merge base, so DrCI cannot tell whether the failure is pre-existing)
    RuntimeError: Command bash /Users/runner/work/_temp/exec_script failed with exit code 65

BROKEN TRUNK - The following job failed but were present on the merge base:

👉 Rebase onto the `viable/strict` branch to avoid these failures

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla

meta-cla Bot commented May 27, 2026

Copy link
Copy Markdown

Hi @devin-lai!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@linux-foundation-easycla

linux-foundation-easycla Bot commented May 27, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: devin-lai / name: Devin Lai (a1552b0)
  • ✅ login: digantdesai / name: Digant Desai (ff0ba0d)

@github-actions

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

@meta-cla

meta-cla Bot commented May 27, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 27, 2026
@meta-cla

meta-cla Bot commented May 27, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!


if(EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER)
target_link_libraries(
coremldelegate PRIVATE portable_ops_lib portable_kernels

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

where else this is linked?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In the top-level CMake configuration, coremldelegate is added to _executorch_backends in CMakeLists.txt:713–715, and then brought into _executor_runner_libs through executorch_backends at CMakeLists.txt:1355–1357. Those libraries are ultimately linked into executor_runner at CMakeLists.txt:1392.
The ops registration library is chosen separately in CMakeLists.txt:1363–1369:

  • optimized_native_cpu_ops_lib when EXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON
  • portable_ops_lib otherwise
    Because of that separation, coremldelegate itself does not need to link against either ops library directly.
    For the standalone CoreML Xcode runner, the setup is also independent of coremldelegate’s CMake dependencies. The script examples/apple/coreml/scripts/build_executor_runner.sh copies libportable_ops_lib.a and libportable_kernels.a into examples/apple/coreml/executor_runner/libraries/, and the Xcode project links them explicitly.
    I also checked several other CMake consumers — including examples/models/llama, examples/models/llava, and examples/devtools. In each case, the ops registration library is selected explicitly before coremldelegate is force-loaded.

@digantdesai digantdesai added the module: build/install Issues related to the cmake and buck2 builds, and to installing ExecuTorch label May 27, 2026
@nil-is-all nil-is-all added the module: coreml Issues related to Apple's Core ML delegation and code under backends/apple/coreml/ label Jun 1, 2026
@digantdesai

Copy link
Copy Markdown
Contributor

LGTM.
@claude review this PR

@claude

claude Bot commented Jun 1, 2026

Copy link
Copy Markdown

Claude finished @digantdesai's task in 1m 1s —— View job


PR Review: Avoid duplicate ops registration in macOS executor_runner

  • Read changed files and understand the diff
  • Verify the top-level CMakeLists.txt linking logic
  • Check for any other references to the removed option
  • Post review feedback

Verdict: LGTM — clean, well-scoped fix.

The change correctly identifies the root cause: the macOS preset enables EXECUTORCH_BUILD_KERNELS_OPTIMIZED, which causes executor_runner to link optimized_native_cpu_ops_lib (via CMakeLists.txt:1363-1364). Meanwhile, coremldelegate was conditionally linking portable_ops_lib + portable_kernels when EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER=ON (which the macos preset set). Since coremldelegate is aggregated into executorch_backends (CMakeLists.txt:715) and force-loaded into executor_runner (CMakeLists.txt:1356), both ops libs ended up in the same binary — duplicate ATen kernel registration, abort before main().

What's removed:

  1. The conditional target_link_libraries(coremldelegate PRIVATE portable_ops_lib portable_kernels) block — delegate doesn't need to carry ops libs
  2. The EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER option definition in default.cmake
  3. The set_overridable_option(EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER ON) in macos.cmake

Verification:

  • No remaining references to EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER anywhere in the repo — confirmed via grep
  • The standalone CoreML executor runner (Xcode-based) stages its own libportable_ops_lib.a via build_executor_runner.sh, independent of this CMake link
  • apple_common.cmake sets EXECUTORCH_BUILD_KERNELS_OPTIMIZED ON, confirming the conflict scenario on all Apple presets that also set EXECUTORCH_BUILD_EXECUTOR_RUNNER ON

No concerns. The option was effectively dead for its stated purpose (building a CoreML executor runner — that target doesn't exist in CMake), and its side effect of linking portable ops into the delegate was actively harmful on macOS.

CI note: The build-android failure appears unrelated to this change — coremldelegate is gated by if(APPLE) and Android builds don't enable CoreML. Worth confirming if that failure reproduces on trunk.


@digantdesai digantdesai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks.

@digantdesai digantdesai merged commit f2252a6 into pytorch:main Jun 2, 2026
483 of 487 checks passed
@metascroy

Copy link
Copy Markdown
Contributor

This looks like it has broken test-coreml-delegate

metascroy added a commit that referenced this pull request Jun 2, 2026
…19949)

Reverts #19804

This looks like it broke test-coreml-delegate
Gasoonjia pushed a commit that referenced this pull request Jun 8, 2026
### Summary

The macOS preset builds `executor_runner` with optimized kernels
enabled, so the top-level runner link logic already selects
`optimized_native_cpu_ops_lib` as the ops registration library.

`coremldelegate` was also linking `portable_ops_lib` and
`portable_kernels` through `EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER`.
Since `coremldelegate` is included through `executorch_backends`,
`executor_runner` could force-load both `portable_ops_lib` and
`optimized_native_cpu_ops_lib`. Their generated static initializers
register overlapping ATen kernels, causing `executor_runner` to abort
before `main()` with a duplicate registration error.

This removes the CoreML-side ops-lib link and removes the obsolete
`EXECUTORCH_COREML_BUILD_EXECUTOR_RUNNER` preset option. The CoreML
executor runner under `examples/apple/coreml/executor_runner` is not a
CMake target, so this option was not actually building that runner.

### Compatibility

The `coreml_executor_runner` built by
`examples/apple/coreml/scripts/build_executor_runner.sh` is unaffected.
That script builds the relevant CMake targets, then stages
`libportable_ops_lib.a` and `libportable_kernels.a` into
`examples/apple/coreml/executor_runner/libraries/`. The Xcode project
links those archives directly, independent of `libcoremldelegate.a`'s
internal link list, so the Xcode-built runner keeps working through its
own link line.

Other CMake consumers of `coremldelegate` already select an ops
registration library independently before force-loading
`coremldelegate`, so they are unaffected by removing the private
portable-kernel link from the delegate. Non-Apple platforms do not build
`coremldelegate` because `backends/apple/coreml/CMakeLists.txt` is gated
by `if(APPLE)`. The iOS and iOS-simulator presets never set the removed
option.

### Test plan

```bash
cmake --preset macos
cmake --build cmake-out --target executor_runner --config Debug -j
./cmake-out/Debug/executor_runner
cmake --build cmake-out --target coremldelegate --config Debug -j
```

Verified the `executor_runner` link line no longer contains
`libportable_ops_lib.a` or unprefixed `libportable_kernels.a`.
`liboptimized_native_cpu_ops_lib.a` is still force-loaded.
`liboptimized_portable_kernels.a` is still present, which is expected
because it is one of `optimized_native_cpu_ops_lib`'s kernel libraries.

Running without `--model_path` now reaches `main()`, resets the
threadpool, and fails only on the expected missing `model.pte` path
instead of aborting during static kernel registration.

Authored with Claude.

cc @larryliu0820 @GregoryComer @kimishpatel @YifanShenSZ @cymbalrush
@metascroy

Co-authored-by: Digant Desai <digantdesai@meta.com>
Gasoonjia pushed a commit that referenced this pull request Jun 8, 2026
…19949)

Reverts #19804

This looks like it broke test-coreml-delegate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ciflow/trunk CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. module: build/install Issues related to the cmake and buck2 builds, and to installing ExecuTorch module: coreml Issues related to Apple's Core ML delegation and code under backends/apple/coreml/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants