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
316 lines
9.4 KiB
Python
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)
|