@@ -176,6 +176,9 @@ def check_module_exists(module_path):
176176_aimdo_initialized_devices = set ()
177177if isinstance (current_device , torch .device ) and current_device .type == "cuda" and current_device .index is not None :
178178 _aimdo_initialized_devices .add (current_device .index )
179+ _aimdo_readiness_cache = {}
180+ _aimdo_readiness_warning_keys = set ()
181+ _aimdo_legacy_fallback_devices = set ()
179182
180183def set_current_device (device ):
181184 """Set the current device context for MultiGPU operations."""
@@ -330,8 +333,100 @@ def current_stream_device_aware(device):
330333 logger .info ("[MultiGPU] Patched comfy.model_management.current_stream to honor CUDA device arguments" )
331334 return True
332335
336+ def _aimdo_device_ready (device ):
337+ """Return True/False for known aimdo readiness, or None when it cannot be probed."""
338+ if not getattr (comfy .memory_management , "aimdo_enabled" , False ):
339+ return False
340+
341+ target_device = _coerce_torch_device (device )
342+ if target_device is None or target_device .type != "cuda" or target_device .index is None :
343+ return False
344+ if _aimdo_readiness_cache .get (target_device .index ) is True :
345+ return True
346+
347+ try :
348+ from comfy_aimdo import control as aimdo_control
349+ get_devctx = getattr (aimdo_control , "get_devctx" , None )
350+ if not callable (get_devctx ):
351+ warning_key = (target_device .index , "missing_get_devctx" )
352+ if warning_key not in _aimdo_readiness_warning_keys :
353+ logger .warning ("[MultiGPU] comfy_aimdo.control.get_devctx missing; device readiness is unverified" )
354+ _aimdo_readiness_warning_keys .add (warning_key )
355+ _aimdo_readiness_cache [target_device .index ] = None
356+ return None
357+ get_devctx (target_device .index )
358+ _aimdo_readiness_cache [target_device .index ] = True
359+ return True
360+ except RuntimeError as exc :
361+ if "not initialized" in str (exc ).lower ():
362+ _aimdo_readiness_cache [target_device .index ] = False
363+ return False
364+ warning_key = (target_device .index , str (exc ))
365+ if warning_key not in _aimdo_readiness_warning_keys :
366+ logger .warning (f"[MultiGPU] Unexpected comfy_aimdo readiness failure for { target_device } : { exc } " )
367+ _aimdo_readiness_warning_keys .add (warning_key )
368+ _aimdo_readiness_cache [target_device .index ] = None
369+ return None
370+ except Exception as exc :
371+ warning_key = (target_device .index , str (exc ))
372+ if warning_key not in _aimdo_readiness_warning_keys :
373+ logger .warning (f"[MultiGPU] Unexpected comfy_aimdo readiness failure for { target_device } : { exc } " )
374+ _aimdo_readiness_warning_keys .add (warning_key )
375+ _aimdo_readiness_cache [target_device .index ] = None
376+ return None
377+
378+ def _extract_model_patcher_load_device (args , kwargs ):
379+ """Resolve the effective ModelPatcher load_device from current and future call shapes."""
380+ if "load_device" in kwargs :
381+ return kwargs ["load_device" ]
382+ if len (args ) >= 2 :
383+ return args [1 ]
384+ get_torch_device = getattr (mm , "get_torch_device" , None )
385+ if callable (get_torch_device ):
386+ return get_torch_device ()
387+ return None
388+
389+ def _patch_dynamic_model_patcher_for_aimdo_devices ():
390+ """Route DynamicVRAM only to CUDA devices aimdo actually initialized."""
391+ dynamic_patcher = getattr (comfy .model_patcher , "ModelPatcherDynamic" , None )
392+ if dynamic_patcher is None :
393+ return False
394+ dynamic_new = getattr (dynamic_patcher , "__new__" , None )
395+ if not callable (dynamic_new ):
396+ return False
397+ if getattr (dynamic_new , "_multigpu_aimdo_device_guard" , False ):
398+ return False
399+
400+ def dynamic_patcher_new_with_aimdo_device_guard (cls , * args , ** kwargs ):
401+ target_device = _coerce_torch_device (_extract_model_patcher_load_device (args , kwargs ))
402+ aimdo_ready = _aimdo_device_ready (target_device )
403+ if (
404+ getattr (comfy .memory_management , "aimdo_enabled" , False )
405+ and target_device is not None
406+ and target_device .type == "cuda"
407+ and target_device .index is not None
408+ and aimdo_ready is not True
409+ ):
410+ if target_device .index not in _aimdo_legacy_fallback_devices :
411+ reason = (
412+ "no context"
413+ if aimdo_ready is False
414+ else "unverified context"
415+ )
416+ logger .warning (f"[MultiGPU] comfy_aimdo has { reason } for { target_device } ; using legacy ModelPatcher" )
417+ _aimdo_legacy_fallback_devices .add (target_device .index )
418+ return comfy .model_patcher .ModelPatcher (* args , ** kwargs )
419+
420+ return dynamic_new (cls , * args , ** kwargs )
421+
422+ dynamic_patcher_new_with_aimdo_device_guard ._multigpu_aimdo_device_guard = True
423+ dynamic_patcher_new_with_aimdo_device_guard ._multigpu_original = dynamic_new
424+ dynamic_patcher .__new__ = staticmethod (dynamic_patcher_new_with_aimdo_device_guard )
425+ logger .info ("[MultiGPU] Patched ModelPatcherDynamic to guard aimdo device coverage" )
426+ return True
427+
333428def _initialize_aimdo_visible_cuda_devices ():
334- """Ensure DynamicVRAM initializes every visible CUDA device once when enabled ."""
429+ """Configure MultiGPU behavior around comfy-aimdo's initialized CUDA devices ."""
335430 if not getattr (comfy .memory_management , "aimdo_enabled" , False ):
336431 logger .info ("[MultiGPU] DynamicVRAM not enabled; skipping multi-device aimdo initialization" )
337432 return False
@@ -345,6 +440,44 @@ def _initialize_aimdo_visible_cuda_devices():
345440 logger .warning ("[MultiGPU] comfy_aimdo unavailable during multi-device initialization" )
346441 return False
347442
443+ device_ids = list (range (torch .cuda .device_count ()))
444+ ready_device_ids = []
445+ unverified_device_ids = []
446+ for device_id in device_ids :
447+ ready = _aimdo_device_ready (torch .device ("cuda" , device_id ))
448+ if ready is None :
449+ unverified_device_ids .append (device_id )
450+ continue
451+ if ready :
452+ ready_device_ids .append (device_id )
453+
454+ _aimdo_initialized_devices .clear ()
455+ _aimdo_initialized_devices .update (ready_device_ids )
456+
457+ if len (ready_device_ids ) == len (device_ids ):
458+ logger .info (f"[MultiGPU] comfy_aimdo already initialized for CUDA devices { device_ids } " )
459+ return False
460+
461+ if ready_device_ids :
462+ logger .warning (
463+ "[MultiGPU] comfy_aimdo initialized CUDA devices "
464+ f"{ ready_device_ids } , not every visible device { device_ids } ; "
465+ "leaving initialized devices on DynamicVRAM and falling back per-device elsewhere"
466+ )
467+ elif unverified_device_ids :
468+ logger .warning (
469+ "[MultiGPU] comfy_aimdo readiness could not be verified for CUDA devices "
470+ f"{ unverified_device_ids } ; falling back to legacy ModelPatcher per device"
471+ )
472+ else :
473+ logger .warning (
474+ "[MultiGPU] comfy_aimdo has no initialized CUDA devices; "
475+ "falling back to legacy ModelPatcher per device"
476+ )
477+ _patch_dynamic_model_patcher_for_aimdo_devices ()
478+ if len (device_ids ) > 1 :
479+ return False
480+
348481 init_device = getattr (aimdo_control , "init_device" , None )
349482 if not callable (init_device ):
350483 logger .warning ("[MultiGPU] comfy_aimdo.control.init_device missing; skipping multi-device initialization" )
@@ -357,8 +490,10 @@ def _initialize_aimdo_visible_cuda_devices():
357490 logger .info (f"[MultiGPU] Initializing comfy_aimdo for CUDA device { device_index } " )
358491 initialized = bool (init_device (device_index ))
359492 logger .info (f"[MultiGPU] comfy_aimdo init_device({ device_index } ) -> { initialized } " )
493+ _aimdo_readiness_cache [device_index ] = initialized
360494 if initialized :
361495 _aimdo_initialized_devices .add (device_index )
496+ _aimdo_legacy_fallback_devices .discard (device_index )
362497 initialized_any = True
363498
364499 return initialized_any
0 commit comments