perf-daemon.py
import subprocess, logging, sys, time, signal
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [perf-daemon] %(message)s",
handlers=[logging.StreamHandler(sys.stdout)]
)
log = logging.getLogger("perf-daemon")
CONTAINER_MAP = {
"sunshine": "gaming",
"ollama": "llm",
"open-webui": "llm",
"jellyfin": "video",
"tdarr": "video",
}
PRIORITY = {"gaming": 4, "llm": 3, "video": 2, "balanced": 1}
active: dict[str, str] = {}
_current_profile = None
def running_containers() -> list[str]:
try:
r = subprocess.run(
["docker", "ps", "--format", "{{.Names}}"],
capture_output=True, text=True, timeout=5
)
return r.stdout.strip().splitlines()
except Exception:
return []
def best_profile() -> str:
if not active:
return "balanced"
return max(active.values(), key=lambda w: PRIORITY.get(w, 0))
def apply(profile: str) -> None:
global _current_profile
if profile == _current_profile:
return
log.info(f"Switching to '{profile}' (active: {dict(active)})")
try:
subprocess.run(["/usr/local/bin/perf-mode", profile], timeout=10)
_current_profile = profile
except Exception as e:
log.error(f"Failed to apply profile '{profile}': {e}")
def handle_event(action: str, name: str) -> None:
wl = CONTAINER_MAP.get(name)
if wl is None:
return
prev = best_profile()
if action == "start":
active[name] = wl
log.info(f"Container '{name}' started → workload '{wl}'")
elif action in ("die", "stop", "kill"):
if name in active:
del active[name]
log.info(f"Container '{name}' stopped → workload '{wl}' removed")
new = best_profile()
if new != prev:
apply(new)
def init_from_running() -> None:
log.info("Scanning currently running containers...")
for name in running_containers():
wl = CONTAINER_MAP.get(name)
if wl:
active[name] = wl
log.info(f" Found running: '{name}' → '{wl}'")
profile = best_profile()
log.info(f"Initial profile: '{profile}'")
apply(profile)
def main() -> None:
signal.signal(signal.SIGTERM, lambda *_: sys.exit(0))
init_from_running()
log.info("Listening for Docker events...")
while True:
try:
proc = subprocess.Popen(
[
"docker", "events",
"--filter", "type=container",
"--filter", "event=start",
"--filter", "event=die",
"--filter", "event=stop",
"--filter", "event=kill",
"--format", "{{.Action}} {{.Actor.Attributes.name}}",
],
stdout=subprocess.PIPE, text=True
)
for line in proc.stdout:
line = line.strip()
if not line:
continue
parts = line.split(" ", 1)
if len(parts) == 2:
handle_event(parts[0], parts[1])
except Exception as e:
log.error(f"Docker events error: {e} — retrying in 5s")
time.sleep(5)
if __name__ == "__main__":
main()