The Python bindings cannot run a program that uses non-CPU planned memory
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5k
- Forks
- 1.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 581
Description
What happens
A program exported for the CUDA backend loads fine from Python and then fails at execute:
RuntimeError: method->execute() failed with error 0x12
with this from the backend just before it:
Tensor 0 has device_type=CUDA but its data pointer 0x3190c080 is not backed by CUDA
device memory (cudaPointerGetAttributes err=0, cudaMemoryType=0)
cudaMemoryType=0 means host memory. The tensor being complained about is the method's own
planned input buffer, not anything the caller passed in.
The same program works from C++
This is the part that isolates it. One .pte file, two callers, same machine, same installed
package:
C++ application using Module exit 0, output matches eager PyTorch exactly (0.000e+00)
Python bindings method->execute() failed with error 0x12
Since the file is identical, the difference is in how each side allocates the method's planned
memory.
Why
extension/pybindings/pybindings.cpp allocates planned memory as host buffers:
std::vector<std::vector<uint8_t>> non_const_buffers_;
HierarchicalAllocator non_const_allocator_;
There is no device allocator involved. When a program's memory plan asks for device memory, the
bindings hand it host memory anyway, so the tensor is tagged as living on the device while its
storage is on the host. The backend checks this and refuses, which is the right behaviour: the
alternative is reading host memory from a GPU kernel.
The C++ path goes through the runtime's own memory planning, which consults the DeviceAllocator
that the CUDA backend registers, so the same program gets real device memory there.
Reproducing
import torch
from executorch.backends.cuda.cuda_partitioner import CudaPartitioner
from executorch.exir import to_edge_transform_and_lower
class Net(torch.nn.Module):
def forward(self, x, y):
return torch.relu(x * y + x) * 2.0
example = (torch.randn(4, 16), torch.randn(4, 16))
program = to_edge_transform_and_lower(
torch.export.export(Net().eval(), example), partitioner=[CudaPartitioner([])]
).to_executorch()
open("model.pte", "wb").write(program.buffer)
from executorch.runtime import Runtime
method = Runtime.get().load_program("model.pte").load_method("forward")
method.execute([example[0], example[1]]) # error 0x12
An elementwise model is used on purpose: a linear layer sends the export through a matrix multiply
that needs a GEMM backend for the target GPU, and on some GPUs there is none, which fails export
for an unrelated reason.
Tested on Linux aarch64 with CUDA 13.0 and CUDA 12.6, and it does not look device specific.
What would fix it
The bindings need to allocate planned memory through the registered DeviceAllocator when the
memory plan asks for a non-CPU memory space, the way the C++ runtime already does. A clear error
naming the unsupported memory space would be an improvement on its own, since the current failure
reads as a bad input tensor rather than as an unsupported configuration.
Happy to help if someone more familiar with the bindings has a preferred shape for the fix.
cc @Gasoonjia @digantdesai
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in extension/pybindings/pybindings.cpp and compare its planned-memory allocation with the C++ runtime path that uses the registered DeviceAllocator. Reproduce the CUDA example from the issue, then trace how the memory plan selects storage for non-CPU memory. Done means the Python binding executes the exported elementwise CUDA program successfully with device-backed planned memory, or reports a clear unsupported-memory-space error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- backend, machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100