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

109 lines
3.9 KiB
Python

"""Tests for perfxpert.tools.counters."""
import pytest
from perfxpert.knowledge import load_yaml
from perfxpert.tools import counters
from perfxpert.tools._class import ToolClass
def _arch_with_limit_for(block: str, needed: int = 1) -> str:
arch_limits = load_yaml("pmc_limits")["gpu_arch_limits"]
return next(gfx_id for gfx_id, limits in arch_limits.items() if limits.get(block, 0) >= needed)
def test_lookup_info_known_counter():
gfx_id = _arch_with_limit_for("SQ")
info = counters.lookup_info("SQ_WAVES", gfx_id=gfx_id)
assert info["name"] == "SQ_WAVES"
assert info["block"] == "SQ"
assert info["block_limit"] == load_yaml("pmc_limits")["gpu_arch_limits"][gfx_id]["SQ"]
def test_lookup_info_unknown_raises():
with pytest.raises(KeyError):
counters.lookup_info("DEFINITELY_NOT_A_COUNTER")
def test_validate_splits_tcc_derived_into_own_passes():
"""FETCH_SIZE + WRITE_SIZE must each be in their own pass (anti-Sakana)."""
result = counters.validate_for_gpu(
["SQ_WAVES", "GRBM_COUNT", "FETCH_SIZE", "WRITE_SIZE"],
gpu_arch=_arch_with_limit_for("SQ"),
)
assert result["ok"]
# FETCH_SIZE and WRITE_SIZE must be in separate passes
fetch_passes = [p for p in result["fixed_passes"] if "FETCH_SIZE" in p]
write_passes = [p for p in result["fixed_passes"] if "WRITE_SIZE" in p]
assert len(fetch_passes) == 1
assert len(write_passes) == 1
assert fetch_passes[0] != write_passes[0]
def test_validate_multi_pass_returns_escalation_guidance():
"""Multi-pass plans must include concrete escalation guidance."""
result = counters.validate_for_gpu(
["SQ_WAVES", "GRBM_COUNT", "FETCH_SIZE", "WRITE_SIZE"],
gpu_arch=_arch_with_limit_for("SQ"),
)
escalation = result["escalation"]
assert escalation["required"] is True
assert escalation["pass_count"] == 3
assert escalation["pmc_groups_path"] == "pmc_groups.txt"
assert escalation["pmc_groups"] == [
"pmc: SQ_WAVES GRBM_COUNT",
"pmc: FETCH_SIZE",
"pmc: WRITE_SIZE",
]
commands = {cmd["tool"]: cmd["full_command"] for cmd in escalation["commands"]}
assert commands["rocprof-compute"] == "rocprof-compute profile -- ./app"
assert commands["rocprofv3"] == "rocprofv3 -i pmc_groups.txt -- ./app"
def test_validate_single_pass_does_not_emit_escalation():
"""Single-pass plans should remain simple and omit escalation."""
result = counters.validate_for_gpu(
["SQ_WAVES", "GRBM_COUNT"],
gpu_arch=_arch_with_limit_for("SQ"),
)
assert result["fixed_passes"] == [["SQ_WAVES", "GRBM_COUNT"]]
assert result["escalation"] is None
def test_validate_for_gpu_uses_arch_specific_regular_block_limit():
catalog = load_yaml("counter_catalog")
sq_counters = [entry["name"] for entry in catalog if entry["block"] == "SQ"]
gfx_id = _arch_with_limit_for("SQ", needed=len(sq_counters))
result = counters.validate_for_gpu(sq_counters, gpu_arch=gfx_id)
assert result["fixed_passes"] == [sq_counters]
assert result["escalation"] is None
def test_analysis_pmc_split_uses_same_arch_specific_limit():
from perfxpert.analysis.pmc import _split_pmc_into_passes
catalog = load_yaml("counter_catalog")
sq_counters = [entry["name"] for entry in catalog if entry["block"] == "SQ"]
gfx_id = _arch_with_limit_for("SQ", needed=len(sq_counters))
commands = _split_pmc_into_passes(
sq_counters,
base_flags=[],
base_args=[],
output_dir="./out",
output_prefix="profile",
description="Collect counters",
gpu_arch=gfx_id,
)
assert [arg["value"] for arg in commands[0]["args"] if arg["name"] == "--pmc"] == [" ".join(sq_counters)]
assert len(commands) == 1
def test_is_read_only_class():
assert counters.lookup_info.__tool_class__ == ToolClass.READ_ONLY
assert counters.validate_for_gpu.__tool_class__ == ToolClass.READ_ONLY