Skip to content

Expose backend options in the Python runtime - #23576

Merged
shoumikhin merged 1 commit into
pytorch:mainfrom
shoumikhin:pybind-backend-options
Oct 8, 2026
Merged

shoumikhin merged 1 commit into
pytorch:mainfrom
shoumikhin:pybind-backend-options

Conversation

@shoumikhin

@shoumikhin shoumikhin commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Backends take options in two ways. Some options apply to the whole process, set with executorch::runtime::set_option. Others apply to one program, passed when it loads with a LoadBackendOptionsMap, as Module::load does. The C++, Android and Apple APIs expose both. The Python runtime exposes neither, so Python code cannot turn on a backend option, such as a shared scratch buffer, or pass a load-time option to a delegate.

Change

Add the same two paths to the Python runtime:

runtime = Runtime.get()
runtime.backend_registry.set_option("XnnpackBackend", {"weight_cache_enabled": True})
program = runtime.load_program(
    "model.pte",
    backend_options={"XnnpackBackend": {"workspace_sharing_mode": 1}},
)
  • BackendRegistry.set_option and get_option wrap the C++ free functions of the same names.
  • Runtime.load_program takes backend_options, keyed by backend name. Every method loaded from that program receives them, as with Module::load.
  • Option values are bools, ints or strings, with the same length limits as the C++ API. Any other type raises TypeError, and an out of range value raises ValueError, naming the option.

Test plan

New tests, using XNNPACK so they run in the CPU jobs:

  • set_option then get_option returns the new value, and the original value is restored afterwards.
  • A value XNNPACK refuses, an unsupported Python type, and an unknown backend (for both set_option and get_option) raise errors.
  • A program loaded with a valid workspace_sharing_mode runs and matches eager.
  • A program loaded with a mode XNNPACK does not have fails to load, which shows the load options reach the backend.

@shoumikhin shoumikhin added the release notes: api Changes to public facing apis (any interfaces, pybinded runtime methods, etc.) label Oct 8, 2026
@pytorch-bot

pytorch-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

🔗 Helpful Links

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

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

✅ No Failures

As of commit 49f1807 with merge base d87fb11 (image):
💚 Looks good so far! There are no failures yet. 💚

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

@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 Oct 8, 2026
@shoumikhin
shoumikhin marked this pull request as ready for review October 8, 2026 05:52
Copilot AI balanced review requested due to automatic review settings October 8, 2026 05:52

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Gasoonjia

Gasoonjia commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

why do we need two paths for backend option setting, instead of only runtime.load_program?

@shoumikhin

Copy link
Copy Markdown
Contributor Author

Because backends read options from two different places in C++, and neither replaces the other.

  • set_option reaches the backend's set_option override. It changes process-wide state, and it can be called at any time, with no program involved. For example, XnnpackBackend turns its shared weight cache on and off this way, and the Qualcomm backend sets its log level. A load option never reaches that override, so load_program alone cannot set these.
  • load_program(backend_options=...) fills the LoadBackendOptionsMap that Module::load uses. The backend reads it in init with get_runtime_spec, for that one program only. For example, XnnpackBackend reads a per program workspace_sharing_mode this way, and other programs keep their own setting.

Some keys are meant for only one of the two. The Torch-TensorRT delegate, for example, accepts use_shared_activation_scratch only through set_option and refuses use_shared_engines there, since that one is load-only.

So this mirrors the C++ API, where both exist: executorch::runtime::set_option and Module::load(LoadBackendOptionsMap). Android and Apple expose the load path the same way.

@shoumikhin
shoumikhin force-pushed the pybind-backend-options branch from ce2a946 to c093a37 Compare October 8, 2026 06:14
Copilot AI balanced review requested due to automatic review settings October 8, 2026 06:14

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Gasoonjia Gasoonjia 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.

LGTM, thanks! A couple of small suggestions:

  1. Type errors in to_backend_options: any value that isn't bool/int goes through py::cast<std::string>, so a float or None raises an opaque pybind cast_error that doesn't name the offending key, and bytes is silently accepted as a string. The same applies to out-of-range ints and to a non-dict per-backend value (e.g. {"XnnpackBackend": 1}). Could we check the types explicitly and raise TypeError/ValueError that names the key?

  2. Tests: consider adding cases for an unsupported value type (e.g. float) and for get_option on an unknown backend. In test_load_options_reach_the_backend, the mode=1 case doesn't by itself show that the option was applied; the mode=3 failure is what proves the plumbing. Splitting it into two tests or adding a comment would make that clearer.

Backends take options in two ways: process-wide through
executorch::runtime::set_option, and per load through the
LoadBackendOptionsMap that Module::load passes to every method. The C++,
Android and Apple APIs expose both. The Python runtime exposed neither, so
a Python program could not turn on an option such as a shared scratch
buffer, or pass a load-time option to a delegate.

Add the same two paths to the Python runtime:

    runtime = Runtime.get()
    runtime.backend_registry.set_option("XnnpackBackend", {"weight_cache_enabled": True})
    program = runtime.load_program(
        "model.pte",
        backend_options={"XnnpackBackend": {"workspace_sharing_mode": 1}},
    )

BackendRegistry.set_option and get_option wrap the C++ free functions.
Runtime.load_program takes backend_options, keyed by backend name, and
every method loaded from that program receives them, as with
Module::load. Option values are bools, ints or strings, with the same
length limits as the C++ API. Any other value type raises TypeError and an
out of range value raises ValueError, naming the option.
Copilot AI balanced review requested due to automatic review settings October 8, 2026 06:31
@shoumikhin
shoumikhin force-pushed the pybind-backend-options branch from c093a37 to 49f1807 Compare October 8, 2026 06:31

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@shoumikhin
shoumikhin merged commit 5566917 into pytorch:main Oct 8, 2026
225 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. release notes: api Changes to public facing apis (any interfaces, pybinded runtime methods, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants