Files
gpu-rent/src/gpu_rent/remote/tune_swarm_perf.py
T
Leonid Pershin 97abc7985e Update configuration and environment probing for improved flexibility and compatibility
- Modified the `load_config` function to allow launch preferences in `gpu-rent.vars` to override `.env` settings for non-secret variables, enhancing user control.
- Updated the list of Python candidates in `stack_env_probe.py` to include additional paths for ComfyUI, improving the detection of Python environments.
- Added new pip candidates in `tune_swarm_perf.py` to support various ComfyUI installations, ensuring better compatibility with different setups.
2026-08-21 09:06:27 +03:00

174 lines
5.7 KiB
Python

#!/usr/bin/env python3
"""First-boot Swarm/Comfy performance tune: sageattention ExtraArgs + pip libs.
Idempotent. Marker: /mnt/swarm_data/.gpu-rent-perf-tuned
Re-runs if GPU uuid changed.
"""
from __future__ import annotations
import json
import os
import re
import subprocess
import sys
from pathlib import Path
DATA = Path("/mnt/swarm_data")
GPU_JSON = DATA / ".gpu-rent-gpu.json"
MARKER = DATA / ".gpu-rent-perf-tuned"
BACKENDS = DATA / "Data" / "Backends.fds"
COMFY_VENV_CANDIDATES = [
DATA / "dlbackend" / "ComfyUI" / "venv" / "bin" / "pip",
DATA / "dlbackend" / "comfy" / "venv" / "bin" / "pip",
DATA / "dlbackend" / "comfy" / "ComfyUI" / "venv" / "bin" / "pip",
Path("/opt/swarmui/dlbackend/ComfyUI/venv/bin/pip"),
Path("/opt/swarmui/dlbackend/comfy/venv/bin/pip"),
Path("/opt/swarmui/dlbackend/comfy/ComfyUI/venv/bin/pip"),
]
def load_gpu() -> dict:
if not GPU_JSON.is_file():
return {}
try:
return json.loads(GPU_JSON.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return {}
def tier_notes(gpu: dict) -> dict:
"""Mirror gpu_rent.perf_tiers.swarm_tune_for (stdlib-only on VM)."""
vram = int(gpu.get("vram_mib") or 0)
gib = vram / 1024.0
if gib < 16:
tier = "low"
elif gib < 24:
tier = "mid"
elif gib < 48:
tier = "high"
else:
tier = "ultra"
cap = str(gpu.get("compute_cap") or "0.0")
try:
parts = cap.split(".")
maj, mnr = int(parts[0]), int(parts[1]) if len(parts) > 1 else 0
ampere = (maj, mnr) >= (8, 0)
except ValueError:
ampere = False
use_sage = ampere and tier in {"mid", "high", "ultra"}
return {
"tier": tier,
"use_sage": use_sage,
"extra_args": "--use-sage-attention" if use_sage else "",
"uuid": str(gpu.get("uuid") or ""),
"name": str(gpu.get("name") or ""),
}
def find_pip() -> Path | None:
for p in COMFY_VENV_CANDIDATES:
if p.is_file():
return p
# glob
for p in DATA.glob("dlbackend/**/venv/bin/pip"):
return p
return None
def patch_backends_extra_args(extra: str) -> bool:
"""Ensure ExtraArgs contains sage flag for Comfy self-start backends."""
if not extra:
return False
if not BACKENDS.is_file():
print(f"no {BACKENDS} yet — skip ExtraArgs (Comfy not registered)")
return False
text = BACKENDS.read_text(encoding="utf-8")
if "--use-sage-attention" in text:
print("Backends.fds already has --use-sage-attention")
return False
lines = text.splitlines()
changed = False
out = []
for line in lines:
if re.match(r"^(\s*)ExtraArgs:\s*$", line) or re.match(r"^(\s*)ExtraArgs:\s*\"\"\s*$", line):
indent = re.match(r"^(\s*)", line).group(1)
out.append(f"{indent}ExtraArgs: {extra}")
changed = True
elif re.match(r"^(\s*)ExtraArgs:\s+", line) and "--use-sage-attention" not in line:
out.append(line.rstrip() + f" {extra}")
changed = True
else:
out.append(line)
if not changed:
print("Backends.fds: no ExtraArgs field patched")
return False
BACKENDS.write_text("\n".join(out) + "\n", encoding="utf-8")
print(f"patched {BACKENDS} ExtraArgs += {extra}")
return True
def pip_install_sage(pip: Path) -> bool:
print(f"pip install triton sageattention via {pip}")
env = dict(os.environ)
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
cmd = [str(pip), "install", "-U", "triton", "sageattention"]
try:
subprocess.check_call(cmd, env=env)
print("triton + sageattention installed")
return True
except subprocess.CalledProcessError as exc:
print(f"WARN: pip install failed ({exc}) — ExtraArgs NOT applied")
return False
def main() -> int:
gpu = load_gpu()
plan = tier_notes(gpu)
prev = {}
if MARKER.is_file():
try:
prev = json.loads(MARKER.read_text(encoding="utf-8"))
except json.JSONDecodeError:
prev = {}
same_gpu = bool(prev.get("uuid") and prev.get("uuid") == plan["uuid"])
if same_gpu and prev.get("extra_args") == plan["extra_args"]:
if prev.get("pip_ok") or not plan["use_sage"]:
print(f"perf tune already applied for {plan['name']} ({plan['tier']})")
return 0
if same_gpu and plan["use_sage"] and prev.get("pip_ok") is False:
print("perf tune: retry (previous pip_ok=false — sage/triton ещё не встали)")
print(f"perf tune: {plan['name']} tier={plan['tier']} sage={plan['use_sage']}")
pip_ok = not plan["use_sage"]
restarted_needed = False
if plan["use_sage"]:
pip = find_pip()
if pip:
pip_ok = pip_install_sage(pip)
else:
print("Comfy venv pip not found yet — will retry next up")
pip_ok = False
# Only patch ExtraArgs when wheels installed — otherwise Comfy may break.
if pip_ok and patch_backends_extra_args(plan["extra_args"]):
restarted_needed = True
marker = {
"uuid": plan["uuid"],
"name": plan["name"],
"tier": plan["tier"],
"extra_args": plan["extra_args"] if pip_ok else "",
"pip_ok": pip_ok,
"restart_needed": restarted_needed,
}
MARKER.write_text(json.dumps(marker, indent=2) + "\n", encoding="utf-8")
print("wrote", MARKER)
if restarted_needed:
print("RESTART_SWARMUI=1")
return 0
if __name__ == "__main__":
sys.exit(main())