94 lines
3.5 KiB
Python
94 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from scripts.measure_gpio_status import MeasurementError, percentile_95, validate_samples
|
|
|
|
|
|
def sample(frames: int, *, misses: int = 0, fault: int = 0, performance: bool = True):
|
|
return {
|
|
"screen": {
|
|
"driver_status": {
|
|
"actual_refresh_rate_hz": 97.4,
|
|
"panel_scan_rate_hz": 97.4,
|
|
"scans_per_frame": 1,
|
|
"completed_frames": frames,
|
|
"completed_scans": frames,
|
|
"deadline_misses": misses,
|
|
"oe_pulse_faults": fault,
|
|
"oe_forced_blanks": 0,
|
|
"driver_error": None,
|
|
"oe_timing_error": None,
|
|
"safeoff_error": None,
|
|
"cpu_affinity": 3,
|
|
"cpu_affinity_active": True,
|
|
"realtime_priority": 50,
|
|
"realtime_priority_active": True,
|
|
"memory_locked": True,
|
|
}
|
|
},
|
|
"system": {
|
|
"performance_mode": {
|
|
"requested": performance,
|
|
"effective": performance,
|
|
"current_governors": {"policy0": "performance" if performance else "schedutil"},
|
|
"restore_governors": {"policy0": "schedutil"},
|
|
}
|
|
},
|
|
}
|
|
|
|
|
|
def test_gpio_measurement_accepts_equal_progress_and_fixed_rgb_frame():
|
|
result = validate_samples(
|
|
[sample(100), sample(198), sample(295)],
|
|
performance="on",
|
|
frame_before="same",
|
|
frame_after="same",
|
|
)
|
|
assert result["completed_frames_delta"] == 195
|
|
assert result["deadline_miss_rate"] == 0
|
|
assert percentile_95([1, 2, 3, 100]) == 100
|
|
|
|
|
|
def test_gpio_measurement_rejects_fault_growth_and_changed_frame():
|
|
with pytest.raises(MeasurementError, match="oe_pulse_faults"):
|
|
validate_samples(
|
|
[sample(100), sample(198, fault=1)],
|
|
performance="on",
|
|
frame_before="same",
|
|
frame_after="same",
|
|
)
|
|
with pytest.raises(MeasurementError, match="RGB frame changed"):
|
|
validate_samples(
|
|
[sample(100), sample(198)],
|
|
performance="on",
|
|
frame_before="before",
|
|
frame_after="after",
|
|
)
|
|
|
|
|
|
def test_gpio_measurement_requires_governor_restore_when_off():
|
|
off = [sample(100, performance=False), sample(198, performance=False)]
|
|
validate_samples(off, performance="off", frame_before="same", frame_after="same")
|
|
off[-1]["system"]["performance_mode"]["current_governors"] = {"policy0": "powersave"}
|
|
with pytest.raises(MeasurementError, match="not restored"):
|
|
validate_samples(off, performance="off", frame_before="same", frame_after="same")
|
|
|
|
|
|
def test_preview_performance_unit_is_isolated_and_preserves_realtime_contract():
|
|
source_root = Path(__file__).resolve().parents[1]
|
|
unit = (source_root / "systemd/matrix-screen-controller-preview-perf.service").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert "Conflicts=matrix-screen-controller.service" in unit
|
|
assert "MATRIX_DATA_DIR=/var/tmp/matrix-screen-controller-preview-perf-20260824" in unit
|
|
assert "MATRIX_RUNTIME_DIR=/run/matrix-screen-controller-preview-perf-20260824" in unit
|
|
assert "/var/lib/matrix-screen-controller" not in unit
|
|
assert "CPUAffinity=0 1 2" in unit
|
|
assert "LimitRTPRIO=50" in unit
|
|
assert "LimitMEMLOCK=infinity" in unit
|
|
assert unit.count("hub75_safeoff") == 2
|
|
assert "app.system.performance restore" in unit
|