Rendre la carte autonome, télécharger la pyramide en fond, refermer les trous de zoom et borner les workers GPU par la VRAM
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -294,6 +294,76 @@ def set_active_gpu(gpu_id):
|
||||
_init_gpu()
|
||||
|
||||
|
||||
def force_cpu():
|
||||
"""Interdit le GPU à ce processus (worker en excédent de VRAM).
|
||||
|
||||
Aucun candidat ne survit au filtre et CUDA_VISIBLE_DEVICES vide empêche
|
||||
CuPy de créer un contexte (~300 Mo de VRAM par processus sinon).
|
||||
"""
|
||||
global _restricted_gpu_ids
|
||||
_restricted_gpu_ids = []
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = ''
|
||||
_init_gpu()
|
||||
|
||||
|
||||
# Pic de VRAM d'un worker (Mo) : contexte CUDA (~300) + calage conjoint des
|
||||
# lignes sur CuPy (~70-100 o par point sol en float64, ~15 M points par dalle
|
||||
# 0,2 m + bande de 100 m) + transformée de distance de _fill_nans (indices
|
||||
# int32 ×2 sur ~7000² px ≈ 400 Mo) ; le pool CuPy garde ses blocs entre deux
|
||||
# étapes. Estimation depuis le code, à ajuster par LIDAR_GPU_WORKER_MIB.
|
||||
GPU_WORKER_MIB = int(os.environ.get("LIDAR_GPU_WORKER_MIB", "2048") or 2048)
|
||||
# VRAM laissée libre sur chaque GPU (affichage, autres processus).
|
||||
GPU_RESERVE_MIB = int(os.environ.get("LIDAR_GPU_RESERVE_MIB", "512") or 512)
|
||||
|
||||
|
||||
def gpu_free_mib():
|
||||
"""VRAM libre par GPU (indice hôte → Mo) via nvidia-smi, sans contexte CUDA.
|
||||
|
||||
Dictionnaire vide si la mesure échoue : l'appelant ne borne alors rien.
|
||||
"""
|
||||
try:
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
['nvidia-smi', '--query-gpu=index,memory.free',
|
||||
'--format=csv,noheader,nounits'],
|
||||
capture_output=True, text=True, timeout=15,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return {}
|
||||
free = {}
|
||||
for line in result.stdout.strip().splitlines():
|
||||
parts = [p.strip() for p in line.split(',')]
|
||||
if len(parts) >= 2:
|
||||
free[int(parts[0])] = int(parts[1])
|
||||
return free
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def gpu_worker_slots(gpu_ids, n_workers, free_mib=None):
|
||||
"""Place de chaque worker du pool : indice GPU, -1 (CPU forcé) ou None.
|
||||
|
||||
Chaque GPU reçoit au plus (VRAM libre − réserve) / GPU_WORKER_MIB
|
||||
workers (au moins un), entrelacés entre GPU ; l'excédent tourne en CPU
|
||||
au lieu de saturer la VRAM (OOM). Sans GPU : None partout (choix laissé
|
||||
au worker). VRAM inconnue : round-robin sans borne (comportement
|
||||
historique).
|
||||
"""
|
||||
if not gpu_ids:
|
||||
return [None] * n_workers
|
||||
if free_mib is None:
|
||||
free_mib = gpu_free_mib()
|
||||
if not all(g in free_mib for g in gpu_ids):
|
||||
return [gpu_ids[i % len(gpu_ids)] for i in range(n_workers)]
|
||||
capacity = {g: max(1, (free_mib[g] - GPU_RESERVE_MIB) // GPU_WORKER_MIB)
|
||||
for g in gpu_ids}
|
||||
slots = []
|
||||
for rank in range(max(capacity.values())):
|
||||
slots += [g for g in gpu_ids if capacity[g] > rank]
|
||||
slots = slots[:n_workers]
|
||||
return slots + [-1] * (n_workers - len(slots))
|
||||
|
||||
|
||||
def _gpu_available():
|
||||
"""Check if GPU is usable right now."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user