Files
TheRock/rocm-libraries/shared/rocroller/scripts/kgraph.py
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

227 lines
5.9 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Load kernel graph from the meta data of an assembly file and render it.
Usage:
kgraph.py path/to/assembly.s
this creates a PDF file at path/to/assembly.pdf. To automatically
open it (via xdg-open), pass '-x'.
"""
import argparse
import re
import subprocess
from pathlib import Path
import yaml
from dot_diff import diff_dots
def extract_normalised_asm(path: Path, keep_trailing_comments: bool = False):
"""Extract normalized ASM from assembly file."""
source = path.read_text()
meta = False
asm = []
for line in source.splitlines():
if keep_trailing_comments:
line = line.strip()
if line.startswith("//"):
continue
else:
double_slash = line.find("//")
if double_slash != -1:
line = line[:double_slash]
line = line.rstrip()
if "kernel_graph_dot" in line:
continue
if ".amdgpu_metadata" in line:
meta = True
if line and not meta:
asm.append(line)
if ".end_amdgpu_metadata" in line:
meta = False
return "\n".join(asm)
def extract_asm_dot(path: Path):
"""Extract .kernel_graph meta data from assembly file."""
source = path.read_text()
beginMatch = re.search(r"^---$", source, re.MULTILINE)
endMatch = re.search(r"^\.\.\.$", source, re.MULTILINE)
assert beginMatch is not None
assert endMatch is not None
beginPos = beginMatch.span()[1]
endPos = endMatch.span()[0]
assert beginPos < endPos
meta = yaml.load(source[beginPos:endPos], Loader=yaml.CSafeLoader)
kernel = meta["amdhsa.kernels"][0]
def try_get(key):
if key in kernel:
return kernel[key]
return None
return try_get(".name"), try_get(".kernel_graph_dot"), try_get(".kernel_graph")
def extract_log_dots(path: Path):
source = path.read_text()
source_clean = ""
prev_end = 0
dots = []
for graph in re.finditer("digraph {", source):
this_graph = source[graph.start() :].partition("\n\n")[0]
before_graph = source[prev_end : graph.start()]
source_clean += before_graph
prev_end = graph.start() + len(this_graph)
dots.append(this_graph)
source_clean += source[prev_end:]
return dots, source_clean
def write_dot(dot: str, fname: Path):
out_fname = fname.with_suffix(".dot")
out_fname.write_text(dot)
print(f"Wrote {out_fname}")
return out_fname
def render_dot(fname: Path, dot: str):
"""Render graph."""
with fname.open("w") as out:
subprocess.run(["dot", "-Tpdf"], input=dot.encode(), stdout=out)
print(f"Wrote {fname}")
def open_dot(fname):
subprocess.call(["xdg-open", str(fname)])
def open_code(fname):
subprocess.call(["code", str(fname)])
def process_dot(
dot: str,
out_path: Path,
code_open: bool,
dot_only: bool,
xdg_open: bool,
):
dotfile = write_dot(dot, out_path)
if code_open:
open_code(dotfile)
if not dot_only:
rendered_fname = out_path.with_suffix(".pdf")
render_dot(rendered_fname, dot)
if xdg_open:
open_dot(rendered_fname)
def process_serialized_graph(graph: dict, out_path: Path):
with out_path.with_suffix(".yaml").open("w") as f:
yaml.dump(graph, f, default_flow_style=None, Dumper=yaml.CSafeDumper)
print(f"Wrote {f.name}")
def process_normalized_asm(path: Path, keep_trailing_comments: bool = True):
asm = Path(path.stem + "_normalized.s")
asm.write_text(extract_normalised_asm(path, keep_trailing_comments))
print(f"Wrote {asm}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Extract and render kernel graph.")
parser.add_argument("fname", type=str, help="Assembly or log file name")
parser.add_argument("-d", "--dot-only", default=False, action="store_true")
parser.add_argument(
"-x",
"--xdg-open",
default=False,
action="store_true",
help="Open with xdg-open after generating",
)
parser.add_argument(
"-c",
"--code-open",
default=False,
action="store_true",
help="Open .dot with VSCode after generating",
)
parser.add_argument(
"-o",
"--output",
type=str,
help="Output file base name",
)
parser.add_argument(
"-k",
"--keep-trailing",
default=False,
action="store_true",
help="Keep trailing comments in normalized assembly file.",
)
parser.add_argument(
"--omit_diff",
default=False,
action="store_true",
help="Omit dot diff coloring",
)
args = parser.parse_args()
path = Path(args.fname)
foutput = path
if args.output is not None:
foutput = Path(args.output)
if path.suffix == ".s":
_, dot, graph = extract_asm_dot(path)
process_dot(
dot,
foutput,
args.code_open,
args.dot_only,
args.xdg_open,
)
if graph is not None and not args.dot_only:
process_serialized_graph(graph, foutput)
process_normalized_asm(path, args.keep_trailing)
elif path.suffix == ".log":
dots, source_clean = extract_log_dots(path)
foutput_clean = Path(str(foutput) + "_clean.log")
foutput_clean.write_text(source_clean)
if not args.omit_diff:
dots = diff_dots(dots)
for i, dot in enumerate(dots):
serial_str = f"_{i:04d}"
foutput_serial = Path(str(foutput) + serial_str)
process_dot(
dot,
foutput_serial,
args.code_open,
args.dot_only,
args.xdg_open,
)
else:
print("Unknown file extension")