Skip to content

Commit 7cfcde7

Browse files
authored
Stop importing exir when loading the runtime from Python (pytorch#23301)
Loading the runtime from Python imports the whole exporter. `portable_lib.py` imports `executorch.exir._warnings` only to get `ExperimentalWarning` for one warning. Importing any `executorch.exir` submodule runs `executorch/exir/__init__.py`, which pulls in `torch._dynamo`, Inductor, Triton and torchao. A process that only loads and runs `.pte` files pays for all of that. On a Jetson AGX Thor, in a fresh process after `import torch`, importing the runtime that way adds about 1,900 modules, over 250 MB of resident memory and about 3 seconds. Jetson boards share their memory between the CPU and the GPU, so on a small one like the 8 GB Orin Nano those 250 MB come out of the model's budget. This change raises the same message as a `DeprecationWarning`. `ExperimentalWarning` derives from `DeprecationWarning`, so Python's default filters treat it the same way: hidden by default, shown with `-W default` or under pytest. Only the class name in the printed warning changes. It also drops the now unused `//executorch/exir:_warnings` dependency from the `portable_lib` target, and adds a runtime test that imports `executorch.runtime` in a fresh interpreter and checks that neither `executorch.exir` nor `torch._dynamo` got loaded. Measured on the Thor with a model that runs one TensorRT engine through ExecuTorch, three fresh processes each: | | before | after | | --- | --- | --- | | time to import the runtime and load the program | 3.3 s | 0.24 s | | resident memory added | 758 MB | 522 MB | | per-call latency | unchanged | unchanged | Test plan: the new test fails before this change and passes after it. The runtime and pybindings tests pass. Checked that the warning still prints under `-W default` and stays hidden with the default filters.
1 parent e78c792 commit 7cfcde7

3 files changed

Lines changed: 16 additions & 5 deletions

File tree

‎extension/pybindings/BUCK‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ fbcode_target(_kind = runtime.python_library,
6868
visibility = ["PUBLIC"],
6969
deps = [
7070
":_C",
71-
"//executorch/exir:_warnings",
7271
],
7372
)
7473

‎extension/pybindings/portable_lib.py‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
import sys
1919
import warnings as _warnings
2020

21-
import executorch.exir._warnings as _exir_warnings
22-
21+
# A DeprecationWarning, like exir's ExperimentalWarning, without importing exir.
22+
# Importing it would load the exporter into a process that only runs programs.
2323
_warnings.warn(
2424
"This API is experimental and subject to change without notice.",
25-
_exir_warnings.ExperimentalWarning,
25+
DeprecationWarning,
2626
)
2727

2828
# When installed as a pip wheel, we must import `torch` before trying to import
@@ -107,5 +107,4 @@
107107
# Clean up so that `dir(portable_lib)` is the same as `dir(_C)`
108108
# (apart from some __dunder__ names).
109109
del _torch
110-
del _exir_warnings
111110
del _warnings

‎runtime/test/test_runtime.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
# LICENSE file in the root directory of this source tree.
66

77
import io
8+
import subprocess
9+
import sys
810
import tempfile
911
import unittest
1012
from pathlib import Path
@@ -20,6 +22,17 @@
2022

2123

2224
class RuntimeTest(unittest.TestCase):
25+
def test_runtime_import_does_not_load_the_exporter(self):
26+
# A fresh interpreter, since this process has already imported exir.
27+
probe = (
28+
"import sys; import executorch.runtime; "
29+
"print(sorted(m for m in ('executorch.exir', 'torch._dynamo') if m in sys.modules))"
30+
)
31+
result = subprocess.run(
32+
[sys.executable, "-c", probe], capture_output=True, text=True, check=True
33+
)
34+
self.assertEqual(result.stdout.strip(), "[]")
35+
2336
def test_smoke(self):
2437
ep, inputs = create_program(ModuleAdd())
2538
runtime = Runtime.get()

0 commit comments

Comments
 (0)