Spaces:
Running
Running
File size: 5,906 Bytes
efc2358 0f74380 efc2358 0f74380 efc2358 0f74380 efc2358 c229485 0f74380 c229485 bd11be5 dd17a03 bd11be5 0f74380 efc2358 0f74380 fb223ca 0f74380 efc2358 0f74380 1909c69 0f74380 c229485 fb223ca c229485 fb223ca 0f74380 efc2358 1909c69 0f74380 fb223ca 1909c69 c229485 1909c69 c229485 1909c69 bd11be5 dd17a03 bd11be5 1909c69 c229485 17ac6a1 0f74380 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import platform
import shlex
import subprocess
import tarfile
import tempfile
import urllib.request
from pathlib import Path
import gradio as gr
import nvidia
def find_tool(name):
path = next(p for d in nvidia.__path__ if (p := Path(d) / "cu13/bin" / name).exists())
path.chmod(0o755)
return str(path)
def fetch_legacy_nvdisasm(version):
arch = "linux-sbsa" if platform.machine() == "aarch64" else "linux-x86_64"
name = f"cuda_nvdisasm-{arch}-{version}-archive"
path = Path(tempfile.gettempdir()) / name / "nvdisasm"
if not path.exists():
url = f"https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvdisasm/{arch}/{name}.tar.xz"
with urllib.request.urlopen(url) as r, tarfile.open(fileobj=r, mode="r|xz") as tar:
member = next(m for m in tar if m.name == f"{name}/bin/nvdisasm")
path.parent.mkdir(exist_ok=True)
path.write_bytes(tar.extractfile(member).read())
path.chmod(0o755)
return str(path)
TOOLS = {name: find_tool(name) for name in ("cuobjdump", "nvdisasm")}
# nvdisasm 13.x can't run flow analysis (CFGs) on old-format CUDA ELF (OSABI 0x33, pre-CUDA 13); 12.9 can.
LEGACY_NVDISASM = fetch_legacy_nvdisasm("12.9.88")
OUTPUTS = {
"cuobjdump": ["--dump-sass", "--dump-ptx", "--dump-elf", "--dump-resource-usage", "--dump-elf-symbols",
"--list-elf", "--list-ptx"],
"nvdisasm": ["--print-code", "--output-control-flow-graph", "--output-control-flow-graph-with-basic-blocks"],
}
MODIFIERS = {
"cuobjdump": [],
"nvdisasm": ["--print-instruction-encoding", "--print-life-ranges", "--print-raw", "--print-line-info",
"--print-line-info-inline"],
}
EXTRA_EXAMPLE = {"cuobjdump": "--function vecadd", "nvdisasm": "--emit-json"}
GRAPHVIZ_HEAD = "".join(f'<script src="https://cdn.jsdelivr.net/npm/{lib}"></script>' for lib in (
"d3@7.9.0/dist/d3.min.js", "@hpcc-js/wasm@2.20.0/dist/graphviz.umd.js", "d3-graphviz@5.6.0/build/d3-graphviz.min.js"))
GRAPHVIZ_JS = """
const graph = element.querySelector('.graph');
d3.select(graph).graphviz({useWorker: false, zoom: true}).renderDot(props.value, () => {
const svg = graph.querySelector('svg');
svg.setAttribute('width', '100%');
svg.setAttribute('height', Math.min(svg.viewBox.baseVal.height * 4 / 3, 600));
});
"""
EXAMPLES = sorted(str(p) for p in Path(__file__).with_name("examples").glob("*.cubin"))
def version(exe):
return subprocess.run([exe, "--version"], capture_output=True, text=True).stdout.split("release ")[-1].splitlines()[0]
def is_old_elf(file):
with open(file, "rb") as f:
head = f.read(8)
return head[:4] == b"\x7fELF" and head[7] == 0x33
def executable(tool, file):
return LEGACY_NVDISASM if tool == "nvdisasm" and is_old_elf(file) else TOOLS[tool]
def run_one(tool, args, file):
try:
r = subprocess.run([executable(tool, file), *args, file], capture_output=True, text=True, timeout=60)
except subprocess.TimeoutExpired:
return "Timed out after 60s."
return (r.stdout + r.stderr or "(no output)") + (f"\n[exit code {r.returncode}]" if r.returncode else "")
def run(file, tool, outputs, modifiers, extra):
if file is None:
return {"error": "Upload a cubin first."}
common = [*modifiers, *shlex.split(extra or "")]
return {" ".join(args): run_one(tool, args, file) for args in ([o, *common] for o in outputs)} or \
{" ".join(common) or tool: run_one(tool, common, file)}
def select_tool(tool):
return (gr.CheckboxGroup(OUTPUTS[tool], value=OUTPUTS[tool]),
gr.CheckboxGroup(MODIFIERS[tool], value=[], visible=bool(MODIFIERS[tool])),
gr.Textbox(placeholder=EXTRA_EXAMPLE[tool]))
with gr.Blocks(title="cuobjdump / nvdisasm") as demo:
gr.Markdown("# cuobjdump / nvdisasm\n"
"Disassemble CUDA cubins, fatbins and ELF objects with NVIDIA's tools ("
+ ", ".join(f"`{t}` {version(exe)}" for t, exe in TOOLS.items())
+ f"; old-format CUDA ELF goes to `nvdisasm` {version(LEGACY_NVDISASM)}).")
with gr.Row(equal_height=True):
with gr.Column(scale=1):
file = gr.File(label="cubin / fatbin / CUDA ELF", type="filepath")
with gr.Column(scale=2):
tool = gr.Radio(list(TOOLS), value="cuobjdump", label="Tool")
outputs = gr.CheckboxGroup(OUTPUTS["cuobjdump"], value=OUTPUTS["cuobjdump"], label="Outputs (each runs separately)")
modifiers = gr.CheckboxGroup(MODIFIERS["cuobjdump"], label="Display options (applied to every run)", visible=False)
with gr.Row(equal_height=True):
extra = gr.Textbox(label="Extra arguments", placeholder=EXTRA_EXAMPLE["cuobjdump"], scale=4)
btn = gr.Button("Run", variant="primary", scale=1)
gr.Examples(EXAMPLES, file)
results = gr.State({})
@gr.render(inputs=results)
def show(results):
for label, output in results.items():
if output.startswith("digraph"):
gr.Markdown(f"`{label}` (scroll to zoom, drag to pan)")
gr.HTML(output.replace("\t", " "), head=GRAPHVIZ_HEAD, js_on_load=GRAPHVIZ_JS,
html_template='<div class="graph" style="background:white;'
'border:1px solid var(--border-color-primary)"></div>')
with gr.Accordion(f"{label} (DOT source)", open=False):
gr.Code(output, max_lines=60)
else:
gr.Code(output, label=label, max_lines=60)
tool.change(select_tool, tool, [outputs, modifiers, extra])
(btn.click(lambda: gr.Button("Running…", interactive=False), None, btn)
.then(run, [file, tool, outputs, modifiers, extra], results)
.then(lambda: gr.Button("Run", interactive=True), None, btn))
if __name__ == "__main__":
demo.launch()
|