Files
TheRock/rocm-systems/projects/rocprofiler-compute/tests/test_roofline_analyze.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

316 lines
9.4 KiB
Python

# Copyright (c) Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""Roofline coverage for the ``analyze`` roofline path.
MI200 (gfx90a) tests run through the ``analyze`` CLI and assert that roofline
HTML is generated, including the per-datatype VALU/MFMA legend.
"""
import shutil
import tempfile
from collections.abc import Callable
from pathlib import Path
import common
import pytest
config = {}
config["cleanup"] = True
roofline_dir = "tests/workloads/mem_levels_HBM/MI200"
# =============================================================================
# Roofline HTML generation
# =============================================================================
def test_analyze_generates_roofline_html(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
) -> None:
"""
Analyze generates roofline HTML from existing workload data.
Uses MI200 workload with roofline.csv.
"""
workload_dir = common.setup_workload_dir(roofline_dir)
assert (Path(workload_dir) / "roofline.csv").exists()
code = binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--roofline-data-type",
"FP32",
])
assert code == 0
html_files = list(Path(workload_dir).glob("empirRoof_*.html"))
assert len(html_files) > 0, "Analyze should generate roofline HTML files"
common.clean_output_dir(config["cleanup"], workload_dir)
def test_analyze_roofline_datatype_independently(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
) -> None:
"""
Analyze with multiple data types.
Verifies each datatype can be requested independently.
"""
workload_dir = common.setup_workload_dir(roofline_dir)
assert (Path(workload_dir) / "roofline.csv").exists()
for dtype in ["FP32", "FP64", "BF16"]:
code = binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--roofline-data-type",
dtype,
])
assert code == 0
html_files = list(Path(workload_dir).glob("empirRoof_*.html"))
assert len(html_files) > 0, "Analyze should generate roofline HTML files"
common.clean_output_dir(config["cleanup"], workload_dir)
def test_analyze_roofline_multiple_datatypes_single_invocation(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
) -> None:
"""
Analyze with multiple data types in a single invocation.
Verifies the multi-datatype request path works end to end.
"""
workload_dir = common.setup_workload_dir(roofline_dir)
assert (Path(workload_dir) / "roofline.csv").exists()
code = binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--roofline-data-type",
"FP32",
"FP64",
"BF16",
])
assert code == 0
html_files = list(Path(workload_dir).glob("empirRoof_*.html"))
assert len(html_files) > 0, "Analyze should generate roofline HTML files"
common.clean_output_dir(config["cleanup"], workload_dir)
def test_analyze_missing_roofline_csv_graceful(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
) -> None:
"""
Analyze without roofline.csv should not crash.
Uses a workload directory that has sysinfo.csv but no roofline.csv.
"""
workload_dir = common.setup_workload_dir(roofline_dir)
roofline_csv = Path(workload_dir) / "roofline.csv"
if roofline_csv.exists():
roofline_csv.unlink()
code = binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
])
assert code == 0
common.clean_output_dir(config["cleanup"], workload_dir)
def test_analyze_roofline_idempotent(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
) -> None:
"""
Running analyze twice on the same profiling output should produce
consistent results without errors.
"""
workload_dir = common.setup_workload_dir(roofline_dir)
assert (Path(workload_dir) / "roofline.csv").exists()
analyze_args = [
"analyze",
"--path",
workload_dir,
"--roofline-data-type",
"FP32",
]
code1 = binary_handler_analyze_rocprof_compute(analyze_args)
assert code1 == 0
code2 = binary_handler_analyze_rocprof_compute(analyze_args)
assert code2 == 0
html_files = list(Path(workload_dir).glob("empirRoof_*.html"))
assert len(html_files) > 0, "Analyze should generate roofline HTML files"
common.clean_output_dir(config["cleanup"], workload_dir)
def test_analyze_corrupted_roofline_csv_graceful(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
) -> None:
"""
Analyze with a corrupted roofline.csv should handle gracefully.
"""
with tempfile.TemporaryDirectory() as temp_dir:
workload_dir = Path(temp_dir) / "corrupted_workload"
shutil.copytree(roofline_dir, workload_dir)
roofline_csv = workload_dir / "roofline.csv"
roofline_csv.write_text("this,is,bad,csv")
code = binary_handler_analyze_rocprof_compute([
"analyze",
"-b",
"4",
"--path",
str(workload_dir),
])
assert code == 0
def test_roof_invalid_data_type(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
capsys: pytest.CaptureFixture[str],
) -> None:
"""Invalid --roofline-data-type should be rejected by the analyze argparser."""
workload_dir = common.setup_workload_dir(roofline_dir)
assert (Path(workload_dir) / "roofline.csv").exists()
binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--roofline-data-type",
"INVALID_TYPE",
])
err = capsys.readouterr().err
assert "--roofline-data-type" in err
assert "invalid choice" in err
common.clean_output_dir(config["cleanup"], workload_dir)
def test_roof_invalid_mem_level(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
capsys: pytest.CaptureFixture[str],
) -> None:
"""Invalid --mem-level should be rejected by the analyze argparser."""
workload_dir = common.setup_workload_dir(roofline_dir)
assert (Path(workload_dir) / "roofline.csv").exists()
binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--mem-level",
"INVALID_LEVEL",
])
err = capsys.readouterr().err
assert "--mem-level" in err
assert "invalid choice" in err
common.clean_output_dir(config["cleanup"], workload_dir)
roofline_mem_level_dirs = {
"vL1D": "tests/workloads/mem_levels_vL1D/MI200",
"LDS": "tests/workloads/mem_levels_LDS/MI200",
}
@pytest.mark.parametrize(
"mem_level",
["vL1D", "LDS"],
ids=["vL1D", "LDS"],
)
def test_roof_mem_levels(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
mem_level: str,
) -> None:
"""Analyze with --mem-level generates roofline HTML output."""
workload_src = roofline_mem_level_dirs[mem_level]
if not Path(workload_src).exists():
pytest.skip(f"Workload directory {workload_src} not found")
workload_dir = common.setup_workload_dir(workload_src, param_id=mem_level)
code = binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--mem-level",
mem_level,
])
assert code == 0
html_files = list(Path(workload_dir).glob("empirRoof_*.html"))
assert len(html_files) > 0, "Analyze should generate roofline HTML files"
common.clean_output_dir(config["cleanup"], workload_dir)
# =============================================================================
# Per-datatype HTML output validation
# =============================================================================
# Each datatype must take the correct roofline branch:
# FP64 is dual-path (VALU + MFMA), BF16 is MFMA-only.
DATATYPE_LEGEND_CASES = {
"FP64": {"present": ["Peak VALU-FP64", "Peak MFMA-FP64"], "absent": []},
"BF16": {"present": ["Peak MFMA-BF16"], "absent": ["Peak VALU-BF16"]},
}
@pytest.mark.parametrize("dtype", list(DATATYPE_LEGEND_CASES))
def test_analyze_roofline_datatype_html_legend(
binary_handler_analyze_rocprof_compute: Callable[[list[str]], int],
dtype: str,
) -> None:
"""Per-datatype roofline HTML embeds the expected VALU/MFMA legend.
FP8/FP4/FP6 are intentionally excluded: they are unsupported on the
available gfx90a (MI200) test data and are covered by the unit tests.
"""
workload_dir = common.setup_workload_dir(roofline_dir, param_id=dtype)
assert (Path(workload_dir) / "roofline.csv").exists()
code = binary_handler_analyze_rocprof_compute([
"analyze",
"--path",
workload_dir,
"--roofline-data-type",
dtype,
])
assert code == 0
html_files = list(Path(workload_dir).glob(f"empirRoof_*{dtype}*.html"))
assert len(html_files) > 0, f"Analyze should generate a {dtype} roofline HTML"
html_text = html_files[0].read_text(encoding="utf-8")
for legend in DATATYPE_LEGEND_CASES[dtype]["present"]:
assert legend in html_text, f"{dtype} HTML should contain '{legend}'"
for legend in DATATYPE_LEGEND_CASES[dtype]["absent"]:
assert legend not in html_text, f"{dtype} HTML should not contain '{legend}'"
common.clean_output_dir(config["cleanup"], workload_dir)