Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 60 additions & 16 deletions docs/compatibility.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,67 @@ The following table lists the validated Hyperloom version and component combinat

.. role:: version-start

.. table::
:widths: 6 27 10 10 14 30 3
:align: left
.. list-table::
:header-rows: 1
:widths: 15 30 45 35 20 15 5
:class: compat-matrix format-big-table

+-------------------+---------------------------+------------------------+----------------------------+---------------+-------------+-----------------------------+
| Hyperloom version | Component | GPU | ROCm version | Ubuntu | Python | GitHub |
+===================+===========================+========================+============================+===============+=============+=============================+
| 1.0.0a3 | `TraceLens 0.1.0`_ | Hardware-agnostic | No dependency | OS-independent| >= 3.6 | |tracelens-github| |
+ +---------------------------+------------------------+----------------------------+---------------+-------------+-----------------------------+
| | `GEAK 4.0.0`_ | MI300X, MI325X, MI355X | 6.4.x, 7.0.x, 7.1.x, 7.2.x | 22.04, 24.04 | 3.8, 3.12 | |geak-github| |
+ +---------------------------+------------------------+----------------------------+---------------+-------------+-----------------------------+
| | `IntelliKit 0.1.0`_ | MI300X, MI325X, MI355X | 7.2.x | 22.04, 24.04 | >= 3.10 | |intellikit-github| |
+ +---------------------------+------------------------+----------------------------+---------------+-------------+-----------------------------+
| | `AgentKernelArena 0.2.0`_ | MI300X, MI325X, MI355X | 7.2.x | 22.04, 24.04 | >= 3.10 | |agent-kernel-arena-github| |
+ +---------------------------+------------------------+----------------------------+---------------+-------------+-----------------------------+
| | `Magpie 0.2.0`_ | MI300X, MI325X, MI355X | 7.0.x, 7.1.x, 7.2.x | 22.04, 24.04 | >= 3.10 | |magpie-github| |
+-------------------+---------------------------+------------------------+----------------------------+---------------+-------------+-----------------------------+
* - Hyperloom version
- Component
- GPU
- ROCm version
- Ubuntu
- Python
- GitHub
* - 1.0.0a1
- `TraceLens 0.1.0`_
- Hardware-agnostic
- No dependency
- OS-independent
- >= 3.6
- |tracelens-github|
* - 1.0.0a2
- `TraceLens 0.1.0`_
- Hardware-agnostic
- No dependency
- OS-independent
- >= 3.6
- |tracelens-github|
* - 1.0.0a3
- `TraceLens 0.1.0`_
- Hardware-agnostic
- No dependency
- OS-independent
- >= 3.6
- |tracelens-github|
* - 1.0.0a2
- `GEAK 4.0.0`_
- MI300X, MI325X, MI355X, RX 9070 XT, RX 9070, RX 9060 XT, R9000
- 6.4.x, 7.0.x, 7.1.x, 7.2.x
- 22.04, 24.04
- 3.8, 3.12
- |geak-github|
* - 1.0.0a2
- `IntelliKit 0.1.0`_
- MI300X, MI325X, MI355X
- 7.2.x
- 22.04, 24.04
- >= 3.10
- |intellikit-github|
* - 1.0.0a2
- `AgentKernelArena 0.2.0`_
- MI300X, MI325X, MI355X
- 7.2.x
- 22.04, 24.04
- >= 3.10
- |agent-kernel-arena-github|
* - 1.0.0a2
- `Magpie 0.2.0`_
- MI300X, MI325X, MI355X, RX 9070 XT, RX 9070, RX 9060 XT, R9000
- 7.0.x, 7.1.x, 7.2.x (Linux), 7.3+ (Windows for RDNA4)
- 22.04, 24.04, Win 11
- >= 3.10
- |magpie-github|

.. _TraceLens 0.1.0: https://rocm.docs.amd.com/projects/tracelens/en/docs-0.1.0/
.. _GEAK 4.0.0: https://rocm.docs.amd.com/projects/geak/en/docs-4.0.0/
Expand Down Expand Up @@ -196,3 +239,4 @@ rocm720, prefer ``docker`` mode with
These are recommended defaults, not hard pins. Framework and ROCm versions are
overridable via env (``SGLANG_REF``, ``SGLANG_ROCM_EXTRA``, ``VLLM_VERSION``,
``VLLM_ROCM_VARIANT``) for hosts that need a different pinned stack.

2 changes: 1 addition & 1 deletion src/hyperloom/inference_optimizer/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def _build_parser() -> argparse.ArgumentParser:
opt.add_argument(
"--gpu-type",
type=str.lower,
choices=["mi300x", "mi308x", "mi325x", "mi355x"],
choices=["mi300x", "mi308x", "mi325x", "mi355x", "rx9070xt", "rx9070", "rx9060xt", "r9000"],
default=None,
help="Hint for the real target GPU. The rocm-smi probe always "
"wins when both are present and disagree; a WARN is "
Expand Down
79 changes: 62 additions & 17 deletions src/hyperloom/inference_optimizer/gpu_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,52 @@
from __future__ import annotations

import os
import sys


_AMD_GPU_TYPES = frozenset({"mi300x", "mi308x", "mi325x", "mi355x"})
_AMD_GPU_TYPES = frozenset({
"mi300x", "mi308x", "mi325x", "mi355x",
"rx9070xt", "rx9070", "rx9060xt", "r9000"
})

_GFX_TO_RUNNER: dict[str, str] = {
# gfx arch -> Magpie runner label, so launchers and runtime materializers
# agree on the selected benchmark script.
"gfx942": "mi300x",
"gfx950": "mi355x",
"gfx1201": "rx9070xt",
"gfx1203": "r9000",
"gfx1206": "rx9060xt",
"gfx1207": "rx9070",
}

_AMD_GPU_DISPATCH_IDENTITIES: dict[str, tuple[str, int]] = {
"mi300x": ("gfx942", 304),
"mi308x": ("gfx942", 304),
"mi325x": ("gfx942", 304),
"mi355x": ("gfx950", 256),
"rx9070xt": ("gfx1201", 64),
"r9000": ("gfx1203", 64),
"rx9070": ("gfx1207", 56),
"rx9060xt": ("gfx1206", 32),
}

# GPU types for which Magpie ships a benchmark runner script (sglang_<runner>.sh).
# MI308X/MI325X are mapped to the MI300X runner by _gpu_runner_type(); every
# RDNA4 SKU resolves to itself. The matching rx9xxx runner scripts are shipped
# by the AMD-AGI/Magpie package (see docs/components/magpie.md).
_SHIPPED_MAGPIE_RUNNERS: frozenset[str] = frozenset({
"mi300x", "mi355x",
"rx9070xt", "rx9070", "rx9060xt", "r9000",
})


def _gpu_runner_type(gpu_type: str) -> str:
"""Return the Magpie runner label for a resolved real GPU type."""
"""Return the Magpie runner label for a resolved real GPU type.

MI308X/MI325X collapse to the MI300X runner (shipped as
``sglang_mi300x.sh``); every other supported AMD type resolves to itself.
"""
normalized = str(gpu_type or "").strip().lower()
if normalized in ("mi325x", "mi308x"):
if normalized in ("mi300x", "mi308x", "mi325x"):
return "mi300x"
return normalized

Expand All @@ -51,22 +74,44 @@ def _resolve_gpu_type(


def _autodetect_gpu_type() -> str | None:
"""Return mi300x|mi308x|mi325x|mi355x or None if undetectable."""
"""Return mi300x|mi308x|mi325x|mi355x|rx9070xt|rx9070|rx9060xt|r9000 or None."""
import subprocess

try:
out = subprocess.run(
["rocm-smi", "--showproductname"],
capture_output=True,
text=True,
timeout=5,
).stdout.upper()
for tag in ("MI355X", "MI325X", "MI308X", "MI300X"):
if tag in out:
return tag.lower()
if sys.platform == "win32":
out = subprocess.run(
["hipConfig", "--show-device"],
capture_output=True,
text=True,
timeout=10,
).stdout.upper()
# Match whole device names; bare "RX 9070" (no " XT") must still
# resolve to rx9070 rather than collapsing into the empty set.
for tag in (
"RX 9070 XT", "R9000", "RX 9060 XT",
"RX 9070 ", "RX 9070", "RX 9060",
"MI355X", "MI300X",
):
if tag in out:
return tag.replace("MI", "mi").replace("RX ", "rx").replace(" XT", "xt").replace(" ", "").lower()
# Fallbacks for "AMD Radeon RX 9070" / "AMD Radeon Pro R9000" (full
# product strings) so bare non-XT SKUs are detected.
import re as _re
bare = _re.search(r"AMD\s+Radeon\s+(Pro\s+R9000|RX\s+\d{3,4}\s*XT|RX\s+\d{3,4})\b", out)
if bare:
tok = bare.group(1).replace("Pro ", "Pro_").replace("XT", "xt").replace(" ", "").replace("_", "").replace("RX", "rx").lower()
return "r9000" if "pro" in tok or "r9000" in tok else tok
else:
out = subprocess.run(
["rocm-smi", "--showproductname"],
capture_output=True,
text=True,
timeout=5,
).stdout.upper()
for tag in ("MI355X", "MI325X", "MI308X", "MI300X", "RX9070XT", "RX9070", "RX9060XT", "R9000"):
if tag in out:
return tag.lower()
except (FileNotFoundError, subprocess.TimeoutExpired, PermissionError, OSError):
# rocm-smi missing / slow / not permitted; fall through to the torch
# gcnArchName probe below (autodetect is best-effort).
pass
try:
import torch
Expand Down
97 changes: 97 additions & 0 deletions src/hyperloom/orchestrator/kernel/roofline_ceiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@
"fp4": 10066.4,
"float4": 10066.4,
}
#: RDNA4 vendor-dense peak TFLOPS — per SKU. The four RX 9000-series SKUs do
#: *not* share a single table: AMD's published CU count and game clock differ
#: per SKU (see wiki/RDNA_4). rx9070xt (64 CU @ 2.4 GHz) is the baseline; the
#: other rows are scaled by (CUs * game_clock) so FP32/FP16/FP8 throughput is
#: distinct and correctly ordered: 9070xt > 9000xt > 9070 > 9060xt. Absolute
#: magnitude is preserved for rx9070xt so existing KB recipes stay calibrated.
_RDNA4_PEAK_TFLOPS_RX9070XT: dict[str, float] = {
"bf16": 194.8,
"bfloat16": 194.8,
"fp16": 194.8,
"float16": 194.8,
"fp8": 389.0,
"float8_e4m3fn": 389.0,
"float8_e5m2": 389.0,
"fp32": 14.6,
"float32": 14.6,
"fp64": 0.46,
"float64": 0.46,
"int4": 1557.0,
}


def _rdna4_peak_tflops(cu_count: int, boost_ghz: float, base: dict[str, float]) -> dict[str, float]:
"""Scale a reference RDNA4 (RX 9070 XT, 64 CU @ 2.4 GHz) peak table by
the CU-count × boost-clock ratio for the target SKU."""
ref_cu = 64
ref_ghz = 2.4
scale = (cu_count * boost_ghz) / (ref_cu * ref_ghz)
return {dtype: round(v * scale, 1) for dtype, v in base.items()}


_RDNA4_PEAK_TFLOPS_R9000: dict[str, float] = _RDNA4_PEAK_TFLOPS_RX9070XT
_RDNA4_PEAK_TFLOPS_RX9070: dict[str, float] = _rdna4_peak_tflops(56, 2.07, _RDNA4_PEAK_TFLOPS_RX9070XT)
_RDNA4_PEAK_TFLOPS_RX9060XT: dict[str, float] = _rdna4_peak_tflops(32, 2.53, _RDNA4_PEAK_TFLOPS_RX9070XT)
HW_SPECS: dict[str, dict[str, Any]] = {
"mi300x": {
"hbm_gb": 192.0,
Expand All @@ -79,6 +113,26 @@
"hbm_bw_gbps": 8000.0,
"peak_tflops": _MI355X_PEAK_TFLOPS,
},
"rx9070xt": {
"gddr_gb": 16.0,
"hbm_bw_gbps": 640.0,
"peak_tflops": _RDNA4_PEAK_TFLOPS_RX9070XT,
},
"rx9070": {
"gddr_gb": 16.0,
"hbm_bw_gbps": 640.0,
"peak_tflops": _RDNA4_PEAK_TFLOPS_RX9070,
},
"rx9060xt": {
"gddr_gb": 16.0,
"hbm_bw_gbps": 640.0,
"peak_tflops": _RDNA4_PEAK_TFLOPS_RX9060XT,
},
"r9000": {
"gddr_gb": 32.0,
"hbm_bw_gbps": 640.0,
"peak_tflops": _RDNA4_PEAK_TFLOPS_R9000,
},
}


Expand Down Expand Up @@ -1574,6 +1628,29 @@ def read_baseline_server_args(state: Any) -> str:
"float32": 137.0,
}


#: RDNA4 sustained (achievable) TFLOPS — reference is the RX 9070 XT
#: (64 CU, Navi 48). Other SKUs scaled by (CUs × game_clock) ratio.
#: The R9000 Pro is the workstation twin of the RX 9070 XT (same die,
#: 64 CU) and therefore shares its achievable table.
_RDNA4_ACHIEVABLE_TFLOPS_RX9070XT: dict[str, float] = {
"bf16": 140.0,
"bfloat16": 140.0,
"fp16": 135.0,
"float16": 135.0,
"fp8": 300.0,
"float8_e4m3fn": 300.0,
"float8_e5m2": 300.0,
"fp64": 0.035,
"float64": 0.035,
"int4": 1100.0,
"fp32": 11.0,
"float32": 11.0,
}
_RDNA4_ACHIEVABLE_TFLOPS_R9000: dict[str, float] = _RDNA4_ACHIEVABLE_TFLOPS_RX9070XT
_RDNA4_ACHIEVABLE_TFLOPS_RX9070: dict[str, float] = _rdna4_peak_tflops(56, 2.07, _RDNA4_ACHIEVABLE_TFLOPS_RX9070XT)
_RDNA4_ACHIEVABLE_TFLOPS_RX9060XT: dict[str, float] = _rdna4_peak_tflops(32, 2.53, _RDNA4_ACHIEVABLE_TFLOPS_RX9070XT)

HW_SPECS_ACHIEVABLE: dict[str, dict[str, Any]] = {
"mi300x": {
"hbm_bw_gbps": 5300.0,
Expand All @@ -1590,6 +1667,26 @@ def read_baseline_server_args(state: Any) -> str:
"hbm_gb": 288.0,
"peak_tflops": _MI355X_ACHIEVABLE_TFLOPS,
},
"rx9070xt": {
"hbm_bw_gbps": 640.0,
"hbm_gb": 16.0,
"peak_tflops": _RDNA4_ACHIEVABLE_TFLOPS_RX9070XT,
},
"rx9070": {
"hbm_bw_gbps": 640.0,
"hbm_gb": 16.0,
"peak_tflops": _RDNA4_ACHIEVABLE_TFLOPS_RX9070,
},
"rx9060xt": {
"hbm_bw_gbps": 640.0,
"hbm_gb": 16.0,
"peak_tflops": _RDNA4_ACHIEVABLE_TFLOPS_RX9060XT,
},
"r9000": {
"hbm_bw_gbps": 640.0,
"hbm_gb": 32.0,
"peak_tflops": _RDNA4_ACHIEVABLE_TFLOPS_R9000,
},
}


Expand Down