Skip to content

CUDA backend: a program crashes with an illegal memory access when CUDA device 1 is current #24887

Open

Description

@shoumikhin

A program lowered with CudaPartitioner runs correctly when CUDA device 0 is the current device. When the caller makes device 1 current first (torch.cuda.set_device(1)), execute() fails with an illegal memory access. The delegate seems to use device 0 no matter which device is current.

On a machine with several GPUs, this means a program can only run on the first GPU. The only workaround I found is to pick the GPU with CUDA_VISIBLE_DEVICES, so that the wanted GPU becomes device 0.

Repro

Needs 2 GPUs. It exports a small model once, then runs it in a fresh process with device 0 current and then with device 1 current.

import os, subprocess, sys, tempfile

import torch
from executorch.backends.cuda.cuda_backend import CudaBackend
from executorch.backends.cuda.cuda_partitioner import CudaPartitioner
from executorch.exir import to_edge_transform_and_lower
from executorch.runtime import Runtime


def make_model():
    torch.manual_seed(0)
    return torch.nn.Sequential(torch.nn.Linear(8, 16), torch.nn.ELU(), torch.nn.Linear(16, 4)).eval()


if len(sys.argv) == 1:
    folder = tempfile.mkdtemp()
    program = to_edge_transform_and_lower(
        torch.export.export(make_model(), (torch.zeros(1, 8),)),
        partitioner=[CudaPartitioner([CudaBackend.generate_method_name_compile_spec("forward")])],
    ).to_executorch()
    with open(os.path.join(folder, "model.pte"), "wb") as f:
        program.write_to_file(f)
    program.write_tensor_data_to_file(folder)
    # Run each case in a fresh process, because a failed run leaves the CUDA context broken.
    for device in ("0", "1"):
        subprocess.run([sys.executable, __file__, folder, device])
else:
    folder, device = sys.argv[1], int(sys.argv[2])
    torch.cuda.set_device(device)
    method = Runtime.get().load_program(
        os.path.join(folder, "model.pte"), data_path=os.path.join(folder, "aoti_cuda_blob.ptd")
    ).load_method("forward")
    x = torch.randn(1, 8)
    try:
        out = method.execute([x])[0]
        print(f"current device {device}: OK, max error {(out - make_model()(x)).abs().max().item():.1e}")
    except RuntimeError as e:
        print(f"current device {device}: FAILED: {e}")

Output:

current device 0: OK, max error 4.5e-08
[cuda_allocator.cpp:700] cudaFreeAsync failed: an illegal memory access was encountered (ptr=0x402000200, device -1)
Error: CUDA driver error: an illegal memory access was encountered
[cuda_backend.cpp:1202] AOTInductorModelContainerRun failed with error code 1
current device 1: FAILED: method->execute() failed with error 0x1: cudaFreeAsync failed: an illegal memory access was encountered (ptr=0x402000200, device -1); ... AOTInductorModelContainerRun failed with error code 1; CALL_DELEGATE execute failed at instruction 1: 0x1

Expected

The program runs on the current device, or the caller can choose the device when loading the program. If only device 0 is supported, a clear error at load time would help more than a crash.

Environment

  • ExecuTorch 1.6.0+cu132, PyTorch 2.15.0+cu132, Python 3.12
  • 2x NVIDIA A100 80GB, driver 580.126.09, CUDA toolkit 12.8 for the export
  • Linux x86_64

cc @Gasoonjia @digantdesai

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmodule: cudaIssues related to the AOTI CUDA backend

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions