Files
OpenJarvis/tests/telemetry/test_energy_apple.py
T
Jon Saad-FalconandClaude Opus 4.6 24972e3e52 Add Phase 12+13: energy measurement, install polish, PWA, cross-hardware
Phase 12 — Energy Measurement Upgrade:
- EnergyMonitor ABC with multi-vendor support (NVIDIA hw counters,
  AMD amdsmi, Apple zeus-ml, CPU RAPL sysfs)
- EnergyBatch batch-level energy-per-token accounting
- SteadyStateDetector CV-based thermal equilibrium detection
- EnergyBenchmark with warmup phase
- InstrumentedEngine prefers EnergyMonitor over legacy GpuMonitor
- Telemetry store/aggregator extended with energy fields

Phase 13 — Install, Hosting, Cross-Hardware:
- jarvis doctor diagnostic command (8 checks, --json output)
- jarvis init post-setup guidance with engine-specific next steps
- README Quick Start section
- MLX engine backend (Apple Silicon → mlx recommendation)
- AMD VRAM/multi-GPU detection via rocm-smi
- PyTorch MPS device selection in orchestrator trainers
- PWA support (vite-plugin-pwa, service worker, manifest, icons)
- Server static file serving fix for PWA files
- Dockerfile.gpu.rocm + docker-compose.gpu.rocm.yml for ROCm
- Eval framework display module and efficiency metrics

2244 tests pass, 37 skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:09:07 +00:00

160 lines
5.7 KiB
Python

"""Tests for AppleEnergyMonitor -- mock zeus (no real Apple Silicon required)."""
from __future__ import annotations
import time
import types
from unittest.mock import MagicMock, patch
import pytest
# ---------------------------------------------------------------------------
# Helpers: build a fake zeus module
# ---------------------------------------------------------------------------
def _make_fake_zeus():
"""Return a fake zeus.device.soc.apple module with AppleSiliconMonitor."""
# Build the nested module hierarchy
zeus = types.ModuleType("zeus")
zeus_device = types.ModuleType("zeus.device")
zeus_device_soc = types.ModuleType("zeus.device.soc")
zeus_device_soc_apple = types.ModuleType("zeus.device.soc.apple")
mock_monitor_cls = MagicMock()
zeus_device_soc_apple.AppleSiliconMonitor = mock_monitor_cls
zeus.device = zeus_device
zeus_device.soc = zeus_device_soc
zeus_device_soc.apple = zeus_device_soc_apple
return zeus, zeus_device, zeus_device_soc, zeus_device_soc_apple, mock_monitor_cls
# ---------------------------------------------------------------------------
# Tests: available()
# ---------------------------------------------------------------------------
class TestAvailable:
def test_available_false_on_non_darwin(self):
with patch("platform.system", return_value="Linux"):
from openjarvis.telemetry.energy_apple import AppleEnergyMonitor
assert AppleEnergyMonitor.available() is False
def test_available_false_when_zeus_not_importable(self):
import openjarvis.telemetry.energy_apple as mod
orig = mod._ZEUS_APPLE_AVAILABLE
mod._ZEUS_APPLE_AVAILABLE = False
try:
with patch("platform.system", return_value="Darwin"):
assert mod.AppleEnergyMonitor.available() is False
finally:
mod._ZEUS_APPLE_AVAILABLE = orig
# ---------------------------------------------------------------------------
# Tests: energy_method()
# ---------------------------------------------------------------------------
class TestEnergyMethod:
def test_returns_zeus(self):
from openjarvis.telemetry.energy_apple import AppleEnergyMonitor
monitor = AppleEnergyMonitor.__new__(AppleEnergyMonitor)
assert monitor.energy_method() == "zeus"
# ---------------------------------------------------------------------------
# Tests: sample() component breakdown
# ---------------------------------------------------------------------------
class TestSampleComponentBreakdown:
def test_component_energy_extraction(self):
"""Mock begin_window/end_window and verify cpu/gpu/dram/ane extraction."""
mock_measurement = MagicMock()
mock_measurement.cpu_energy = 1.5
mock_measurement.gpu_energy = 3.0
mock_measurement.dram_energy = 0.5
mock_measurement.ane_energy = 2.0
mock_zeus_monitor = MagicMock()
mock_zeus_monitor.begin_window = MagicMock()
mock_zeus_monitor.end_window = MagicMock(return_value=mock_measurement)
from openjarvis.telemetry.energy_apple import AppleEnergyMonitor
monitor = AppleEnergyMonitor.__new__(AppleEnergyMonitor)
monitor._poll_interval_ms = 50
monitor._monitor = mock_zeus_monitor
monitor._initialized = True
with monitor.sample() as result:
time.sleep(0.01)
mock_zeus_monitor.begin_window.assert_called_once()
mock_zeus_monitor.end_window.assert_called_once()
assert result.cpu_energy_joules == pytest.approx(1.5)
assert result.gpu_energy_joules == pytest.approx(3.0)
assert result.dram_energy_joules == pytest.approx(0.5)
assert result.ane_energy_joules == pytest.approx(2.0)
assert result.vendor == "apple"
assert result.energy_method == "zeus"
def test_total_energy_is_sum_of_components(self):
"""total = cpu + gpu + dram + ane."""
mock_measurement = MagicMock()
mock_measurement.cpu_energy = 1.0
mock_measurement.gpu_energy = 2.0
mock_measurement.dram_energy = 0.3
mock_measurement.ane_energy = 0.7
mock_zeus_monitor = MagicMock()
mock_zeus_monitor.begin_window = MagicMock()
mock_zeus_monitor.end_window = MagicMock(return_value=mock_measurement)
from openjarvis.telemetry.energy_apple import AppleEnergyMonitor
monitor = AppleEnergyMonitor.__new__(AppleEnergyMonitor)
monitor._poll_interval_ms = 50
monitor._monitor = mock_zeus_monitor
monitor._initialized = True
with monitor.sample() as result:
pass
expected_total = 1.0 + 2.0 + 0.3 + 0.7
assert result.energy_joules == pytest.approx(expected_total)
# ---------------------------------------------------------------------------
# Tests: sample() with uninitialized monitor
# ---------------------------------------------------------------------------
class TestSampleUninitialized:
def test_uninitialized_monitor_empty_result(self):
"""When monitor is not initialized, sample yields empty result."""
from openjarvis.telemetry.energy_apple import AppleEnergyMonitor
monitor = AppleEnergyMonitor.__new__(AppleEnergyMonitor)
monitor._poll_interval_ms = 50
monitor._monitor = None
monitor._initialized = False
with monitor.sample() as result:
pass
assert result.energy_joules == 0.0
assert result.cpu_energy_joules == 0.0
assert result.gpu_energy_joules == 0.0
assert result.dram_energy_joules == 0.0
assert result.ane_energy_joules == 0.0
assert result.duration_seconds >= 0
assert result.vendor == "apple"