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
246 lines
7.8 KiB
Python
246 lines
7.8 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
from collections import defaultdict
|
|
from collections.abc import Iterable
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
|
|
if __package__ is None or __package__ == "":
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
|
|
from _code_object_paths import code_objects_from_paths
|
|
from rocprof_trace_decoder.att import AttTrace, generate_att_outputs
|
|
from rocprof_trace_decoder.code_index import CodeIndex
|
|
from rocprof_trace_decoder.codegen import generate_code_artifacts
|
|
from rocprof_trace_decoder.rcv import (
|
|
copy_source_snapshots,
|
|
write_code_json,
|
|
write_source_snapshots,
|
|
)
|
|
|
|
ATT_RE = re.compile(r"_shader_engine_(\d+)_(\d+)\.att$", re.IGNORECASE)
|
|
CODE_SUFFIXES = {".out", ".co", ".hsaco"}
|
|
|
|
|
|
@dataclass
|
|
class _Inputs:
|
|
att_files: list[Path] = field(default_factory=list)
|
|
code_objects: list[Path] = field(default_factory=list)
|
|
code_json: Path | None = None
|
|
|
|
|
|
def generate_outputs_from_files(
|
|
files: Iterable[str | Path],
|
|
*,
|
|
output_dir: str | Path | None = None,
|
|
lib_path: str | Path | None = None,
|
|
formats: str = "json,csv",
|
|
base_name: str | None = None,
|
|
decode_markers: bool = True,
|
|
) -> list[Path]:
|
|
inputs = _discover_inputs(files)
|
|
if not inputs.att_files and not inputs.code_objects and inputs.code_json is None:
|
|
raise SystemExit(
|
|
"No .att files, code.json, or code object files were provided or discovered."
|
|
)
|
|
|
|
base_input = _base_input(inputs)
|
|
output_base_name = base_name or base_input.parent.name or "att"
|
|
decode_output_dir = Path(output_dir).expanduser().resolve() if output_dir else None
|
|
|
|
code_json = inputs.code_json
|
|
code_index = None
|
|
source_paths: tuple[Path, ...] = ()
|
|
snapshot_source_dir = code_json.parent if code_json else None
|
|
code_dir = Path(output_dir).expanduser().resolve() if output_dir else _code_dir(inputs)
|
|
generated_code = False
|
|
if inputs.code_objects:
|
|
try:
|
|
code_objects = code_objects_from_paths(inputs.code_objects)
|
|
except ValueError as exc:
|
|
raise SystemExit(str(exc)) from exc
|
|
artifacts = generate_code_artifacts(code_objects)
|
|
code_index = artifacts.code_index
|
|
source_paths = artifacts.source_paths
|
|
code_json = None
|
|
snapshot_source_dir = None
|
|
generated_code = True
|
|
elif code_json is not None:
|
|
code_index = CodeIndex.from_code_json(code_json, load_counts=False)
|
|
|
|
if not inputs.att_files:
|
|
if code_index is not None:
|
|
if generated_code or output_dir:
|
|
code_dir.mkdir(parents=True, exist_ok=True)
|
|
write_code_json(code_dir, code_index)
|
|
write_source_snapshots(source_paths, code_dir)
|
|
return [code_dir]
|
|
return [code_json.parent] if code_json else []
|
|
return [code_json.parent] if code_json else []
|
|
|
|
traces = _traces_from_att_paths(inputs.att_files)
|
|
outputs = generate_att_outputs(
|
|
traces,
|
|
code_index=code_index,
|
|
source_paths=source_paths,
|
|
output_dir=decode_output_dir,
|
|
lib_path=lib_path,
|
|
formats=formats,
|
|
base_name=output_base_name,
|
|
on_warning=_print_warning,
|
|
decode_markers=decode_markers,
|
|
)
|
|
if snapshot_source_dir:
|
|
for output in outputs:
|
|
copy_source_snapshots(snapshot_source_dir, output)
|
|
return outputs
|
|
|
|
|
|
def _print_warning(path: Path, message: str) -> None:
|
|
print(f"Warning: {path}: {message}", file=sys.stderr)
|
|
|
|
|
|
def _discover_inputs(files: Iterable[str | Path]) -> _Inputs:
|
|
out = _Inputs()
|
|
for raw in files:
|
|
path = Path(raw).expanduser().resolve()
|
|
if path.is_dir():
|
|
for child in sorted(path.iterdir()):
|
|
_add_input(out, child, ignore_unknown=True)
|
|
else:
|
|
_add_input(out, path)
|
|
return out
|
|
|
|
|
|
def _base_input(inputs: _Inputs) -> Path:
|
|
if inputs.att_files:
|
|
return inputs.att_files[0]
|
|
if inputs.code_objects:
|
|
return inputs.code_objects[0]
|
|
if inputs.code_json:
|
|
return inputs.code_json
|
|
raise SystemExit("No input files were provided or discovered.")
|
|
|
|
|
|
def _code_dir(inputs: _Inputs) -> Path:
|
|
if inputs.code_objects:
|
|
return inputs.code_objects[0].parent
|
|
return _base_input(inputs).parent
|
|
|
|
|
|
def _add_input(out: _Inputs, path: Path, *, ignore_unknown: bool = False) -> None:
|
|
if not path.exists():
|
|
raise SystemExit(f"Input does not exist: {path}")
|
|
suffix = path.suffix.lower()
|
|
if suffix == ".att":
|
|
out.att_files.append(path)
|
|
elif path.name.lower() == "code.json":
|
|
out.code_json = path
|
|
elif suffix in CODE_SUFFIXES:
|
|
out.code_objects.append(path)
|
|
elif not ignore_unknown:
|
|
raise SystemExit(
|
|
f"Unsupported input type: {path}. Expected .att, code.json, or a code object "
|
|
"(.out, .co, .hsaco)."
|
|
)
|
|
|
|
|
|
def _traces_from_att_paths(paths: Iterable[Path]) -> list[AttTrace]:
|
|
parsed: list[tuple[Path, tuple[int, int] | None]] = []
|
|
used_shader_engines: dict[int, set[int]] = defaultdict(set)
|
|
|
|
for path in paths:
|
|
metadata = _trace_metadata_from_name(path)
|
|
parsed.append((path, metadata))
|
|
if metadata is not None:
|
|
shader_engine, run = metadata
|
|
used_shader_engines[run].add(shader_engine)
|
|
|
|
next_shader_engine: dict[int, int] = defaultdict(int)
|
|
traces: list[AttTrace] = []
|
|
for path, metadata in parsed:
|
|
if metadata is None:
|
|
run = 1
|
|
shader_engine = _next_available_shader_engine(
|
|
used_shader_engines[run],
|
|
next_shader_engine[run],
|
|
)
|
|
used_shader_engines[run].add(shader_engine)
|
|
next_shader_engine[run] = shader_engine + 1
|
|
else:
|
|
shader_engine, run = metadata
|
|
traces.append(AttTrace(path=path, shader_engine=shader_engine, run=run))
|
|
return traces
|
|
|
|
|
|
def _trace_metadata_from_name(path: Path) -> tuple[int, int] | None:
|
|
match = ATT_RE.search(path.name)
|
|
if not match:
|
|
return None
|
|
return int(match.group(1)), int(match.group(2))
|
|
|
|
|
|
def _next_available_shader_engine(used: set[int], start: int) -> int:
|
|
shader_engine = start
|
|
while shader_engine in used:
|
|
shader_engine += 1
|
|
return shader_engine
|
|
|
|
|
|
def build_argparser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(
|
|
description="Decode ATT traces and/or generate ROCprof Compute Viewer code metadata."
|
|
)
|
|
parser.add_argument(
|
|
"files",
|
|
nargs="+",
|
|
help="Mixed list of .att files, code objects (.out/.co/.hsaco), code.json, or directories.",
|
|
)
|
|
parser.add_argument(
|
|
"-d",
|
|
"--dir",
|
|
dest="output_dir",
|
|
help="Output directory. For multiple runs, subdirectories are created here.",
|
|
)
|
|
parser.add_argument("--lib", help="Path to librocprof-trace-decoder.so")
|
|
parser.add_argument(
|
|
"--formats",
|
|
default="json,csv",
|
|
help="Comma-separated outputs. Default: json,csv",
|
|
)
|
|
parser.add_argument(
|
|
"--base-name",
|
|
help="Base name for default ui_output_<name><run> and stats_<...>.csv output names.",
|
|
)
|
|
parser.add_argument(
|
|
"--no-decode-markers",
|
|
action="store_false",
|
|
dest="decode_markers",
|
|
default=True,
|
|
help="Leave packed marker IDs and JSON shaderdata timestamps unchanged.",
|
|
)
|
|
return parser
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
args = build_argparser().parse_args(argv)
|
|
outputs = generate_outputs_from_files(
|
|
args.files,
|
|
output_dir=args.output_dir,
|
|
lib_path=args.lib,
|
|
formats=args.formats,
|
|
base_name=args.base_name,
|
|
decode_markers=args.decode_markers,
|
|
)
|
|
for path in outputs:
|
|
print(path)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|