Skip to content

fix(executorch): move compile_and_save's engines into the program instead of copying them - #5045

Draft
shoumikhin wants to merge 1 commit into
pytorch:mainfrom
shoumikhin:compile-and-save-consume
Draft

shoumikhin wants to merge 1 commit into
pytorch:mainfrom
shoumikhin:compile-and-save-consume

Conversation

@shoumikhin

@shoumikhin shoumikhin commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Depends on pytorch/executorch#25099; lands after it. compile_and_save uses the consume argument that change adds to ExecuTorch's save and write_tensor_data_to_file, so the ExecuTorch pin bump to the first nightly that has it (which also raises the minimum ExecuTorch version) will be added to this PR once #25099 merges. Only the move passes consume; every other save calls ExecuTorch exactly as before.

What is wrong today

compile_and_save writes each engine to a temporary file as soon as it is built. The ExecuTorch save then copies that file into the .pte (or the .ptd), and the file is deleted only when the call returns. So while the program is written, every engine is on disk twice. For a model whose engine is tens of gigabytes, the export needs that much more free disk, and it can fail on a device that has room for the result.

What this change does

  • The backend hands each of these engine files to ExecuTorch as data that owns the file (FileBackedData(path, cleanup=True)). The file is deleted after the save anyway.
  • Inside compile_and_save, the program is written with ExecuTorch's save(file_path, consume=True) and the .ptd with write_tensor_data_to_file(..., consume=True). ExecuTorch then moves each engine into the program, so each engine is on disk once. ExecuTorch does this only when the temporary directory, where the engine files are, is on the same file system as the program. Its save takes only a .pte path, so a program saved under another name is copied as before.
  • With generate_etrecord, the save copies the engines instead. The ETRecord is written after the program and reads the engines, so a move would leave it nothing to read. The program is still written first, as before, so it is kept when the ETRecord can't be written.
  • The docs now say that compile_and_save can write an ETRecord, unlike a plain save of a program with TensorRT engines.

Tests

  • tests/py/dynamo/executorch/test_api.py, on CPU with the lowering stubbed:
    • test_compile_and_save_moves_the_engines: in the offload block that compile_and_save saves in, the program and the .ptd are written with consume=True.
    • test_compile_and_save_copies_the_engines_into_a_path_without_pte: the same with a .bin path writes both without consume.
    • test_compile_and_save_keeps_the_program_when_the_etrecord_fails: in the same block with an ETRecord, the program and the .ptd are written first, without consume, and the .pte is kept when the ETRecord save fails.
    • test_save_executorch_keeps_the_program_when_the_etrecord_fails: the same for a plain save.
    • test_save_executorch_does_not_consume: a plain save writes without consume. The stubbed ExecuTorch rejects any consume other than True, as releases without it do.
  • tests/py/dynamo/executorch/test_compile_and_save.py, on an A100, with ExecuTorch from #25099:
    • the streaming test also checks that each engine reaches ExecuTorch as data that owns its file;
    • test_engines_move_into_the_program_without_a_second_copy: ExecuTorch copied no engine, and both are in the .pte;
    • test_an_etrecord_makes_the_save_copy_the_engines: with an ETRecord, the engine files keep their bytes, and both the .pte and the ETRecord are written.

@meta-cla meta-cla Bot added the cla signed label Nov 14, 2026
@github-actions github-actions Bot added component: tests Issues re: Tests component: api [Python] Issues re: Python API labels Nov 14, 2026
@github-actions
github-actions Bot requested a review from zewenli98 November 14, 2026 22:41
@shoumikhin
shoumikhin force-pushed the compile-and-save-consume branch from 03b81ce to ba01aca Compare November 15, 2026 01:40
@github-actions github-actions Bot added component: core Issues re: The core compiler component: runtime component: dynamo Issues relating to the `torch.compile` or `torch._dynamo.export` paths labels Nov 15, 2026
@shoumikhin
shoumikhin force-pushed the compile-and-save-consume branch 2 times, most recently from 3cf1702 to 306a9de Compare November 15, 2026 07:04
@shoumikhin
shoumikhin marked this pull request as draft November 15, 2026 07:04
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Nov 15, 2026
…tead of copying them

`compile_and_save` writes each engine to a temporary file as soon as it is built. The ExecuTorch
save then copies that file into the `.pte` (or the `.ptd`), and the file is deleted only when the
call returns. So while the program is written, every engine is on disk twice. For a model whose
engine is tens of gigabytes, the copy needs that much more free disk, and an export can fail on a
device that has room for the result.

The backend now hands each of these engine files to ExecuTorch as data that owns the file
(`FileBackedData(path, cleanup=True)`); it is deleted after the save anyway. Inside
`compile_and_save`, the program is then written with ExecuTorch's `save(file_path, consume=True)`
and the `.ptd` with `write_tensor_data_to_file(..., consume=True)`, so ExecuTorch moves each engine
into the program: it copies it back to front and truncates the file as it goes, and each engine is
on disk once. ExecuTorch does this only when the temporary directory, where the engine files are,
is on the same file system as the program; otherwise it copies. Its `save` takes only a `.pte`
path, so a program saved under another name is written as before, with a copy.

With `generate_etrecord`, the save copies the engines instead. The ETRecord is written after the
program and reads the engines, so a move would leave it nothing to read. The program is still
written first, as before, so it is kept when the ETRecord can't be written. The `save` docstring
now says that `compile_and_save` can write an ETRecord.

This needs the `consume` argument of `save` and `write_tensor_data_to_file` from
pytorch/executorch#25099. It lands after that change, together with an ExecuTorch pin that has it,
which also raises the minimum ExecuTorch version. Only the move passes `consume`, so every other save
calls ExecuTorch exactly as before and keeps working with releases that don't have it.

Test plan:

- `tests/py/dynamo/executorch/test_api.py`, CPU, with the lowering stubbed:
  - New `test_compile_and_save_moves_the_engines`: inside `compile_and_save`'s offload block, the
    program and the `.ptd` are written with `consume=True`. It fails without this change.
  - New `test_compile_and_save_copies_the_engines_into_a_path_without_pte`: the same block with a
    `.bin` path writes both without `consume`.
  - New `test_compile_and_save_keeps_the_program_when_the_etrecord_fails`: in the same block with
    an ETRecord, the program and the `.ptd` are written first, without `consume`, and the `.pte`
    is kept when the ETRecord save raises.
  - New `test_save_executorch_keeps_the_program_when_the_etrecord_fails`: the same for a plain
    save.
  - New `test_save_executorch_does_not_consume`: a plain save writes without `consume`. The stubbed
    ExecuTorch raises TypeError for any `consume` other than `True`, as releases without it do, so
    this test fails if a plain save passes `consume=False`.
- `tests/py/dynamo/executorch/test_compile_and_save.py` on an A100:
  - The streaming test now also checks that each engine reaches ExecuTorch as data that owns its
    file.
  - New `test_engines_move_into_the_program_without_a_second_copy` checks that ExecuTorch copied
    no engine and that both are in the `.pte`.
  - New `test_an_etrecord_makes_the_save_copy_the_engines`: with an ETRecord, the engine files
    keep their bytes, and both the `.pte` and the ETRecord are written.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla signed component: api [Python] Issues re: Python API component: core Issues re: The core compiler component: dynamo Issues relating to the `torch.compile` or `torch._dynamo.export` paths component: runtime component: tests Issues re: Tests documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant