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
2 changes: 1 addition & 1 deletion codecarbon/core/gpu_amd.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def is_rocm_system():
"Please install amdsmi to get GPU metrics."
)
AMDSMI_AVAILABLE = False
except AttributeError as e:
except (AttributeError, OSError, KeyError) as e:
amdsmi = None
# In some environments, amdsmi may be present but not properly configured, leading to AttributeError when importing
logger.warning(
Expand Down
73 changes: 73 additions & 0 deletions tests/test_gpu_amd.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,79 @@ def test_get_compute_and_graphics_processes(self):
assert device._get_graphics_processes() == []


class TestAmdsmiImportFailures:
"""Tests for module-level amdsmi import error handling in gpu_amd.py."""

def _import_gpu_amd_with_amdsmi_error(self, error_to_raise):
"""
Simulate a fresh import of codecarbon.core.gpu_amd where importing amdsmi
raises *error_to_raise*. Returns the freshly imported module object.
"""
import builtins
import importlib
import sys

# Remove cached modules so the module body is re-executed
saved = {}
for name in ("amdsmi", "codecarbon.core.gpu_amd"):
if name in sys.modules:
saved[name] = sys.modules.pop(name)

_real_import = builtins.__import__

def _patched_import(name, *args, **kwargs):
if name == "amdsmi":
raise error_to_raise
return _real_import(name, *args, **kwargs)

try:
with mock.patch("builtins.__import__", side_effect=_patched_import):
module = importlib.import_module("codecarbon.core.gpu_amd")
return module
finally:
# Drop the freshly created module entries and restore original state
sys.modules.pop("amdsmi", None)
sys.modules.pop("codecarbon.core.gpu_amd", None)
sys.modules.update(saved)

def test_oserror_sets_amdsmi_unavailable(self):
"""OSError during amdsmi import (e.g. missing libamd_smi.so) must disable AMD GPU support."""
module = self._import_gpu_amd_with_amdsmi_error(
OSError(
"libamd_smi.so: cannot open shared object file: No such file or directory"
)
)
assert module.amdsmi is None
assert module.AMDSMI_AVAILABLE is False

def test_keyerror_sets_amdsmi_unavailable(self):
"""KeyError during amdsmi import (e.g. macOS with amdsmi installed but no ROCm) must disable AMD GPU support."""
module = self._import_gpu_amd_with_amdsmi_error(KeyError("missing_rocm_key"))
assert module.amdsmi is None
assert module.AMDSMI_AVAILABLE is False

def test_attributeerror_sets_amdsmi_unavailable(self):
"""AttributeError during amdsmi import must disable AMD GPU support."""
module = self._import_gpu_amd_with_amdsmi_error(
AttributeError("module 'amdsmi' has no attribute 'amdsmi_init'")
)
assert module.amdsmi is None
assert module.AMDSMI_AVAILABLE is False

def test_import_failure_logs_warning(self):
"""Each import-time failure (OSError/KeyError/AttributeError) must log a warning."""
for error in (
OSError("libamd_smi.so not found"),
KeyError("rocm_key"),
AttributeError("missing attr"),
):
with mock.patch(
"codecarbon.external.logger.logger.warning"
) as warning_mock:
self._import_gpu_amd_with_amdsmi_error(error)
warning_mock.assert_called()


class TestAllGPUDevicesAmd:
def test_init_with_no_amd_handles(self):
from codecarbon.core.gpu import AllGPUDevices
Expand Down
Loading