Source code for spacr.qt.laptop_mode

"""Measure hardware constraints and suppress the ambient backdrop for this process.

Hardware-based decisions use the usable CPU count, physical memory and the
``SPACR_LAPTOP_MODE`` override. GUI startup instead passes an explicit decision
from the selected performance level; its hardware reading is diagnostic.

Suppression affects backdrop rendering. This module does not set worker-thread
limits or analysis parameters, and it does not replace stored animation
preferences.

``apply`` sets ``SPACR_NO_BACKDROP`` when suppression is requested and the
ambient backdrop is enabled. Disabling removes only a suppression created by
this module; a pre-existing crash-recovery override is retained.
"""
from __future__ import annotations

import os
from typing import Dict, List, Optional, Tuple

#: Below this many usable cores, a machine is treated as small. Four is the
#: line because the ambient layer, the blur and the fit all want a core each
#: and the interface still needs one to stay answerable.
SMALL_CORE_COUNT = 4

#: Below this much RAM in GiB, likewise. 8 GiB is where a browser, a Python
#: process holding a plate of images and the compositor stop fitting.
SMALL_MEMORY_GIB = 8.0

#: The environment variable that overrides the decision either way.
#: ``1``/``true``/``on`` forces it on, ``0``/``false``/``off`` forces it off,
#: absent leaves it to the measurement.
OVERRIDE_VARIABLE = "SPACR_LAPTOP_MODE"

_TRUE = {"1", "true", "yes", "on"}
_FALSE = {"0", "false", "no", "off"}


[docs] def usable_cores() -> int: """Return the CPU affinity count, falling back to ``os.cpu_count``. ``os.sched_getaffinity`` accounts for process pinning when available. If it is unavailable or fails, use the reported CPU count instead. The result is at least one; the fallback does not measure affinity limits. """ try: return max(1, len(os.sched_getaffinity(0))) except (AttributeError, OSError): # pragma: no cover - not Linux return max(1, os.cpu_count() or 1)
[docs] def total_memory_gib() -> Optional[float]: """Physical memory in GiB, or None when it cannot be read.""" try: pages = os.sysconf("SC_PHYS_PAGES") size = os.sysconf("SC_PAGE_SIZE") return (pages * size) / (1024 ** 3) except (AttributeError, ValueError, OSError): return None
[docs] def override() -> Optional[bool]: """Parse the environment override; return ``None`` if absent or unrecognized.""" raw = str(os.environ.get(OVERRIDE_VARIABLE, "")).strip().lower() if raw in _TRUE: return True if raw in _FALSE: return False return None
[docs] def measure() -> Dict[str, object]: """Return CPU count, physical memory, threshold flags and the parsed override.""" cores = usable_cores() memory = total_memory_gib() return { "cores": cores, "memory_gib": memory, "few_cores": cores < SMALL_CORE_COUNT, "little_memory": memory is not None and memory < SMALL_MEMORY_GIB, "override": override(), }
[docs] def wanted(reading: Optional[Dict[str, object]] = None) -> Tuple[bool, str]: """Return the hardware-based laptop-mode decision and its explanation. :returns: ``(on, why)``. The reason is always populated, including when the decision is off. An explicit environment override takes precedence over the core-count and physical-memory threshold flags. """ reading = measure() if reading is None else reading chosen = reading.get("override") cores = reading.get("cores") memory = reading.get("memory_gib") seen = (f"{cores} usable core(s)" + (f", {memory:.1f} GiB of memory" if memory else "")) if chosen is True: return True, f"laptop mode: on because {OVERRIDE_VARIABLE} asks for it" if chosen is False: return False, f"laptop mode: off because {OVERRIDE_VARIABLE} asks for it" reasons: List[str] = [] if reading.get("few_cores"): reasons.append(f"fewer than {SMALL_CORE_COUNT} usable cores") if reading.get("little_memory"): reasons.append(f"less than {SMALL_MEMORY_GIB:g} GiB of memory") if reasons: return True, (f"laptop mode: on -- this machine has {seen} " f"({' and '.join(reasons)}). " f"Set {OVERRIDE_VARIABLE}=0 to keep everything on.") return False, (f"laptop mode: off -- this machine has {seen}. " f"Set {OVERRIDE_VARIABLE}=1 to turn it on anyway.")
[docs] def what_it_turns_down() -> Tuple[Tuple[str, str], ...]: """Return the animation and backdrop-blur descriptions used in diagnostics. Each pair contains an effect name and its description for UI notes and logs. This function returns text; :func:`apply` performs the process-local backdrop suppression. """ return ( ("the ambient background animation", "the moving backdrop stops; every colour and control is unchanged"), ("the backdrop blur", "panels sit on a flat ground instead of a blurred one"), )
[docs] def describe() -> str: """Format the hardware-based decision and effect descriptions for diagnostic logs.""" on, why = wanted() lines = [why] if on: lines.append("turned down, and only the drawing:") lines.extend(f" - {what}: {cost}" for what, cost in what_it_turns_down()) lines.append("a run computes exactly the same answer either way.") return "\n".join(lines)
#: The process-local backdrop switch, and the only thing this module turns. #: #: SUPPRESSING IS NOT THE SAME AS DECIDING, and this module used to do the #: second. It called `preferences.set_ambient_enabled(False)`, which is the #: USER'S stored answer -- so on a machine under the core or memory bar, #: every launch overwrote a preference the user had set, and a user who #: turned the animation back on got it taken away again the next time they #: started spaCR, with nothing on the surface to say why. A hardware guess #: was writing into the one row that is supposed to mean "what I chose". #: #: `SPACR_NO_BACKDROP` is the mechanism that already existed for exactly #: this, and `get_ambient_enabled` documents it: process-local, never saved, #: honoured before the stored value, "so the next clean run brings it back #: with nothing for the user to undo". `crash_recovery` uses it after spaCR #: has died on launch twice. A performance constraint is the same shape of #: thing -- true for this run, on this machine, and none of it the user's #: opinion. #: #: Found by the Preferences audit. _NO_BACKDROP = "SPACR_NO_BACKDROP" #: Whether the variable above is OURS to clear. #: #: `crash_recovery` sets the same variable, and it sets it because spaCR has #: already failed to start twice. Turning the mode off must not hand the #: backdrop back to a driver that has crashed on it -- so `apply` clears the #: variable only when this module is what set it. _suppressed_here = False
[docs] def apply(on: Optional[bool] = None) -> Dict[str, object]: """Apply process-local backdrop suppression and report the decision and actions. :param on: explicit decision; ``None`` uses :func:`wanted`, including its hardware reading and environment override. :returns: a mapping with ``on``, ``why`` and ``changed``. ``on`` is the decision; ``changed`` lists actions actually performed and may be empty. Suppression is process-local and does not replace the stored animation preference. Disabling clears only suppression created by this module, retaining any pre-existing crash-recovery override. """ global _suppressed_here if on is None: on, why = wanted() else: why = (f"laptop mode: {'on' if on else 'off'} because the caller " f"asked for it") changed: List[str] = [] if on: try: from . import preferences if preferences.get_ambient_enabled(): os.environ[_NO_BACKDROP] = "1" _suppressed_here = True changed.append("ambient backdrop suppressed for this run") except Exception: # noqa: BLE001 pass elif _suppressed_here: os.environ.pop(_NO_BACKDROP, None) _suppressed_here = False changed.append("ambient backdrop restored") return {"on": on, "why": why, "changed": changed}