Skip to content
Merged
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
20 changes: 18 additions & 2 deletions nodescraper/plugins/inband/amdsmi/amdsmidata.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ class StaticCacheInfoItem(AmdSmiBaseModel):
na_validator = field_validator("cache_size", mode="before")(na_to_none)


_STATIC_CLOCK_FREQ_LEVEL_VALIDATOR_FIELDS = tuple(f"Level_{i}" for i in range(16))


class StaticFrequencyLevels(AmdSmiBaseModel):
"""Static clock frequency levels; each level is normalized to ``ValueUnit``."""

Expand All @@ -534,8 +537,21 @@ class StaticFrequencyLevels(AmdSmiBaseModel):
Level_0: ValueUnit = Field(..., alias="Level 0")
Level_1: Optional[ValueUnit] = Field(default=None, alias="Level 1")
Level_2: Optional[ValueUnit] = Field(default=None, alias="Level 2")

_level_value_unit = field_validator("Level_0", "Level_1", "Level_2", mode="before")(
Level_3: Optional[ValueUnit] = Field(default=None, alias="Level 3")
Level_4: Optional[ValueUnit] = Field(default=None, alias="Level 4")
Level_5: Optional[ValueUnit] = Field(default=None, alias="Level 5")
Level_6: Optional[ValueUnit] = Field(default=None, alias="Level 6")
Level_7: Optional[ValueUnit] = Field(default=None, alias="Level 7")
Level_8: Optional[ValueUnit] = Field(default=None, alias="Level 8")
Level_9: Optional[ValueUnit] = Field(default=None, alias="Level 9")
Level_10: Optional[ValueUnit] = Field(default=None, alias="Level 10")
Level_11: Optional[ValueUnit] = Field(default=None, alias="Level 11")
Level_12: Optional[ValueUnit] = Field(default=None, alias="Level 12")
Level_13: Optional[ValueUnit] = Field(default=None, alias="Level 13")
Level_14: Optional[ValueUnit] = Field(default=None, alias="Level 14")
Level_15: Optional[ValueUnit] = Field(default=None, alias="Level 15")

_level_value_unit = field_validator(*_STATIC_CLOCK_FREQ_LEVEL_VALIDATOR_FIELDS, mode="before")(
coerce_value_unit_input
)

Expand Down
32 changes: 31 additions & 1 deletion test/unit/plugin/test_amdsmi_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# SOFTWARE.
#
###############################################################################
"""Unit tests for amd-smi pydantic models (ROCm 7.13 / legacy JSON shapes)."""
"""Unit tests for amd-smi pydantic models (legacy JSON, ROCm 7.2+ / AMD-SMI 26.2+)."""

from typing import Any, Optional

Expand Down Expand Up @@ -341,6 +341,36 @@ def test_static_frequency_levels_optional_levels():
assert levels.Level_2 is not None and levels.Level_2.value == 1300


def test_static_frequency_levels_accepts_level_three_plus():
"""ROCm 7.2+ / AMD-SMI 26.2+ may expose additional DPM levels (e.g. Level 3)."""
levels = StaticFrequencyLevels.model_validate(
{
"Level 0": "400 MHz",
"Level 1": "800 MHz",
"Level 2": "1000 MHz",
"Level 3": "1143 MHz",
}
)
assert levels.Level_3 is not None
assert levels.Level_3.value == 1143
assert levels.Level_3.unit == "MHz"


def test_static_frequency_levels_legacy_amd_smi_three_levels_only():
"""Legacy static JSON: only Level 0–2 (no Level 3+ keys)."""
levels = StaticFrequencyLevels.model_validate(
{
"Level 0": {"value": 500, "unit": "MHz"},
"Level 1": "900 MHz",
"Level 2": "1300 MHz",
}
)
assert levels.Level_0.value == 500
assert levels.Level_2 is not None and levels.Level_2.value == 1300
assert levels.Level_3 is None
assert levels.Level_15 is None


def test_static_limit_legacy_max_power():
"""Legacy flat max_power field still resolves."""
limit = StaticLimit.model_validate(DUMMY_LIMIT_LEGACY)
Expand Down
Loading