Files
TheRock/rocm-libraries/projects/hipblaslt/utilities/geko/tests/test_optimize.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

233 lines
7.9 KiB
Python

# Copyright Advanced Micro Devices, Inc., or its affiliates.
# SPDX-License-Identifier: MIT
"""Tests for optimize.py CLI interface.
Usage:
python3 -m pytest tests/test_optimize.py \\
--hipblaslt-path /path/to/hipblaslt \\
--workload /path/to/workload.yaml \\
[--hw gfx942]
``--hw`` sets ``configure.py --architecture`` (default: gfx950).
Hint: add -rs to see skip reasons, or -v for verbose output.
``TestPipelineFast`` exercises ``geko.pipeline.run_optimize`` with Tensile/GPU
work mocked; it runs in CI without hipBLASLt. ``TestIntegration`` runs configure
then real optimize (long-running; needs a built hipBLASLt and GPU).
"""
import json
import subprocess
import sys
import warnings
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
import yaml
from geko import pipeline as pipeline_mod
from geko.pipeline import run_optimize
ROOT = Path(__file__).resolve().parents[1]
# Configure step matches test_configure.py; optimize can take much longer (Tensile / GA).
_CONFIGURE_TIMEOUT_S = 600
_OPTIMIZE_TIMEOUT_S = 7200
def _patch_optimize_config(path, n_gen_target=10, pop_size_target=128):
"""Rewrite one generated optimization config with faster GA settings.
Config format is stable: Backend -> Config -> {n_gen, pop_size}.
"""
with path.open("r") as f:
data = yaml.safe_load(f)
if data is None:
return
backend_cfg = data.setdefault("Backend", {}).setdefault("Config", {})
backend_cfg["n_gen"] = n_gen_target
backend_cfg["pop_size"] = pop_size_target
with path.open("w") as f:
yaml.safe_dump(data, f, sort_keys=False)
# ---------------------------------------------------------------------------
# Fast pipeline test (mocked optim / merge / analyze)
# ---------------------------------------------------------------------------
class TestPipelineFast:
"""Call ``run_optimize`` with heavy steps stubbed; no real tuning or benchmarks."""
def test_main_completes_with_mocks(self, tmp_path):
"""Full control-flow: validation, state flags, mocked run → merge → analyze."""
hip = tmp_path / "hipblaslt_stub"
hip.mkdir()
workdir = tmp_path / "workdir"
(workdir / "optimizations").mkdir(parents=True)
from geko.schemas import RunState
dummy_input = tmp_path / "workload_stub.yaml"
dummy_input.write_text("# stub\n")
state = RunState.create(dummy_input)
state.configured = True
state.dump(workdir / "run_state.json")
merged = MagicMock()
def _dump_libs(target):
p = Path(target)
p.mkdir(parents=True, exist_ok=True)
(p / "merged_stub.yaml").write_text(
"library_name: stub\nlibrary_type: tensile\nsolutions: []\nsizes: []\n"
)
merged.dump.side_effect = _dump_libs
mock_run = MagicMock()
mock_analyze = MagicMock(return_value=None)
mock_merge = MagicMock(return_value=merged)
with patch.object(pipeline_mod.optim, "run", mock_run), patch.object(
pipeline_mod.optim.utils,
"check_progress",
side_effect=[(1, 1, 0), (1, 1, 0)],
), patch.object(pipeline_mod.library, "merge_solutions", mock_merge), patch.object(
pipeline_mod.optim,
"analyze",
mock_analyze,
):
run_optimize(str(hip), workdir=str(workdir), devices=[0], verbose=0)
mock_run.assert_called_once()
ca = mock_run.call_args
assert ca.args[0] == Path(hip)
assert ca.args[1] == workdir / "optimizations"
assert ca.kwargs["devices"] == [0]
mock_merge.assert_called_once()
mock_analyze.assert_called_once()
with (workdir / "run_state.json").open() as f:
final_state = json.load(f)
assert final_state["configured"] is True
assert final_state["optimized"] is True
# ---------------------------------------------------------------------------
# End-to-end integration test
# ---------------------------------------------------------------------------
@pytest.mark.slow
class TestIntegration:
"""Run configure.py then optimize.py against a real workload and hipBLASLt repo.
Usage:
python3 -m pytest tests/test_optimize.py \\
--hipblaslt-path ~/rocm-libraries/projects/hipblaslt \\
--workload tests/test_data/workload.yaml \\
[--hw gfx942]
"""
def test_full_cli_run(self, hipblaslt_path, workload_path, hw_arch, tmp_path):
"""Configure then optimize subprocesses complete (uses conftest CLI options)."""
if hipblaslt_path is None or workload_path is None:
msg = "Skipped: requires --hipblaslt-path and --workload CLI options"
warnings.warn(msg, stacklevel=1)
pytest.skip(msg)
hip = Path(hipblaslt_path)
workload = Path(workload_path)
if not hip.is_dir():
msg = f"Skipped: hipBLASLt path not found: {hip}"
warnings.warn(msg, stacklevel=1)
pytest.skip(msg)
if not workload.is_file():
msg = f"Skipped: workload file not found: {workload}"
warnings.warn(msg, stacklevel=1)
pytest.skip(msg)
workdir = tmp_path / "workdir"
client_build = (tmp_path / "build_tmp").resolve()
run_cwd = str(tmp_path.resolve())
# Absolute paths so subprocess cwd=tmp_path does not break relative CLI args.
configure_py = str((ROOT / "scripts" / "configure.py").resolve())
optimize_py = str((ROOT / "scripts" / "optimize.py").resolve())
hip_abs = str(hip.resolve())
workload_abs = str(workload.resolve())
workdir_abs = str(workdir.resolve())
cfg = subprocess.run(
[
sys.executable,
configure_py,
workload_abs,
"--hipblaslt",
hip_abs,
"--workdir",
workdir_abs,
"--architecture",
hw_arch,
],
cwd=run_cwd,
capture_output=True,
text=True,
timeout=_CONFIGURE_TIMEOUT_S,
)
assert cfg.returncode == 0, (
f"configure.py exited with code {cfg.returncode}\n"
f"--- stdout ---\n{cfg.stdout[-2000:]}\n"
f"--- stderr ---\n{cfg.stderr[-2000:]}"
)
assert workdir.is_dir()
assert (workdir / "optimizations").is_dir()
config_files = pipeline_mod.optim.utils.list_optimization_configs(workdir / "optimizations")
assert len(config_files) > 0, "Expected config files but workdir is empty"
for f in config_files:
# Patch config so it runs faster, independent of original defaults.
_patch_optimize_config(Path(f), n_gen_target=10, pop_size_target=128)
opt = subprocess.run(
[
sys.executable,
optimize_py,
"--hipblaslt",
hip_abs,
"--workdir",
workdir_abs,
"--client_build_dir",
str(client_build),
"--devices",
"0",
"--n_slots",
"1",
],
cwd=run_cwd,
capture_output=True,
text=True,
timeout=_OPTIMIZE_TIMEOUT_S,
)
assert opt.returncode == 0, (
f"optimize.py exited with code {opt.returncode}\n"
f"--- stdout ---\n{opt.stdout[-2000:]}\n"
f"--- stderr ---\n{opt.stderr[-2000:]}"
)
state_path = workdir / "run_state.json"
assert state_path.is_file()
with state_path.open() as f:
state = json.load(f)
assert state.get("configured") is True
assert state.get("optimized") is True
generated = list(workdir.rglob("*"))
assert len(generated) > 0, "Expected output files but workdir is empty"