Files
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

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())