Spaces:
Runtime error
Runtime error
| import glob | |
| import os | |
| import shutil | |
| import subprocess | |
| import sys | |
| import tempfile | |
| import gradio as gr | |
| ARCHITECTURES = ["sm_70", "sm_75", "sm_80", "sm_86", "sm_89", "sm_90"] | |
| DEFAULT_MODEL = """\ | |
| import torch | |
| class Model(torch.nn.Module): | |
| def forward(self, x, y): | |
| return torch.relu(x + y) | |
| model = Model() | |
| inputs = (torch.randn(4, 4), torch.randn(4, 4)) | |
| torch.onnx.export(model, inputs, 'model.onnx', opset_version=17) | |
| """ | |
| def _run(cmd: list[str], label: str, timeout: int) -> tuple[str, bool]: | |
| try: | |
| r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) | |
| if r.returncode != 0: | |
| return f"{label} failed:\n\n{r.stderr.strip()}", False | |
| return r.stdout, True | |
| except subprocess.TimeoutExpired: | |
| return f"{label} timed out ({timeout}s).", False | |
| def compile_pipeline(code: str, arch: str) -> tuple[str, str, str, str, str | None, str | None]: | |
| if not code.strip(): | |
| return "Error: no code provided.", "", "", "", None, None | |
| try: | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| src = os.path.join(tmpdir, "model_def.py") | |
| onnx_path = os.path.join(tmpdir, "model.onnx") | |
| mlir_path = os.path.join(tmpdir, "model.mlir") | |
| vmfb_path = os.path.join(tmpdir, "model.vmfb") | |
| exec_dir = os.path.join(tmpdir, "exec") | |
| cubin_path = os.path.join(tmpdir, "kernel.cubin") | |
| os.makedirs(exec_dir) | |
| with open(src, "w") as f: | |
| f.write(code) | |
| py_cmd = [sys.executable, src] | |
| import_cmd = ["iree-import-onnx", onnx_path, "-o", mlir_path] | |
| compile_cmd = [ | |
| "iree-compile", mlir_path, | |
| "--iree-hal-target-backends=cuda", | |
| f"--iree-cuda-target={arch}", | |
| f"--iree-hal-dump-executable-files-to={exec_dir}", | |
| "-o", vmfb_path, | |
| ] | |
| cmds = "\n".join(" ".join(c) for c in [py_cmd, import_cmd, compile_cmd]) | |
| # PyTorch → ONNX | |
| r = subprocess.run(py_cmd, capture_output=True, text=True, timeout=60, cwd=tmpdir) | |
| if r.returncode != 0: | |
| err = f"PyTorch export failed:\n\n{r.stderr.strip()}" | |
| return cmds, err, err, err, None, None | |
| # ONNX → MLIR | |
| out, ok = _run(import_cmd, "iree-import-onnx", 60) | |
| if not ok: | |
| return cmds, out, out, out, None, None | |
| mlir_text = open(mlir_path).read() if os.path.exists(mlir_path) else "(no MLIR output)" | |
| # MLIR → VMFB, PTX dumped to exec_dir | |
| out, ok = _run(compile_cmd, "iree-compile", 120) | |
| if not ok: | |
| return cmds, mlir_text, out, out, None, None | |
| ptx_files = sorted(glob.glob(os.path.join(exec_dir, "**", "*.ptx"), recursive=True)) | |
| if not ptx_files: | |
| return cmds, mlir_text, "No PTX files produced.", "No PTX to disassemble.", None, None | |
| ptx_text = "\n\n".join(open(p).read() for p in ptx_files) | |
| # PTX → CUBIN → SASS (first PTX file) | |
| ptxas_cmd = ["ptxas", f"--gpu-name={arch}", ptx_files[0], "-o", cubin_path] | |
| cuobjdump_cmd = ["cuobjdump", "--dump-sass", cubin_path] | |
| cmds += "\n" + " ".join(ptxas_cmd) + "\n" + " ".join(cuobjdump_cmd) | |
| _, ok = _run(ptxas_cmd, "ptxas", 30) | |
| sass_text = _run(cuobjdump_cmd, "cuobjdump", 30)[0] if ok else "ptxas failed; SASS unavailable." | |
| ptx_tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".ptx") | |
| ptx_tmp.write(ptx_text.encode()) | |
| ptx_tmp.close() | |
| cubin_tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".cubin") | |
| cubin_tmp.close() | |
| if ok and os.path.exists(cubin_path): | |
| shutil.copy(cubin_path, cubin_tmp.name) | |
| cubin_out = cubin_tmp.name | |
| else: | |
| cubin_out = None | |
| return cmds, mlir_text, ptx_text, sass_text, ptx_tmp.name, cubin_out | |
| except FileNotFoundError as e: | |
| return "", "", f"Tool not found: {e}\n\nEnsure iree-compiler is installed.", "", None, None | |
| except Exception as e: | |
| return "", "", f"Unexpected error: {e}", "", None, None | |
| with gr.Blocks(title="PyTorch → SASS Explorer") as demo: | |
| gr.Markdown( | |
| "# PyTorch → SASS Explorer\n" | |
| "Write a PyTorch model that exports to `model.onnx`, pick a GPU architecture, " | |
| "and trace the full compilation pipeline: PyTorch → ONNX → IREE MLIR → PTX → SASS." | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| code_input = gr.Code( | |
| label="PyTorch Model", language="python", | |
| value=DEFAULT_MODEL, lines=20, | |
| ) | |
| with gr.Column(scale=1): | |
| arch = gr.Dropdown(label="GPU Architecture", choices=ARCHITECTURES, value="sm_80") | |
| btn = gr.Button("Compile", variant="primary") | |
| cmds_out = gr.Code(label="Commands", language="shell", lines=4, interactive=False) | |
| mlir_out = gr.Code(label="MLIR", language=None, lines=10, max_lines=10, interactive=False) | |
| with gr.Row(): | |
| ptx_out = gr.Code(label="PTX", language=None, lines=10, max_lines=10, interactive=False) | |
| sass_out = gr.Code(label="SASS", language=None, lines=10, max_lines=10, interactive=False) | |
| with gr.Row(): | |
| ptx_file = gr.File(label="Download PTX", interactive=False) | |
| cubin_file = gr.File(label="Download CUBIN", interactive=False) | |
| btn.click(compile_pipeline, [code_input, arch], [cmds_out, mlir_out, ptx_out, sass_out, ptx_file, cubin_file]) | |
| if __name__ == "__main__": | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |