Skip to content

Commit 1ed48eb

Browse files
Try to fix the model reloading issue some people have.
1 parent 6880614 commit 1ed48eb

3 files changed

Lines changed: 39 additions & 14 deletions

File tree

comfy/model_management.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ def get_torch_device_name(device):
616616
#Freeing registerables on pressure does imply a GPU sync, so go big on
617617
#the hysteresis so each expensive sync gives us back a good chunk.
618618
REGISTERABLE_PIN_HYSTERESIS = 2048 * 1024 * 1024
619+
WINDOWS_PIN_EVICTION_SWAP_PERCENT = 5.0
620+
WINDOWS_PIN_EVICTION_EMERGENCY_AVAILABLE = 512 * 1024 ** 2
619621

620622
def module_size(module):
621623
module_mem = 0
@@ -642,6 +644,15 @@ def free_pins(size, evict_active=False):
642644
size -= freed
643645
return freed_total
644646

647+
def should_free_pins_for_ram_pressure(shortfall):
648+
if shortfall <= 0:
649+
return False
650+
if not WINDOWS:
651+
return True
652+
if psutil.virtual_memory().available < WINDOWS_PIN_EVICTION_EMERGENCY_AVAILABLE:
653+
return True
654+
return psutil.swap_memory().percent >= WINDOWS_PIN_EVICTION_SWAP_PERCENT
655+
645656
def ensure_pin_budget(size, evict_active=False):
646657
if args.high_ram:
647658
return True

comfy_execution/caching.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,8 @@ async def ensure_subcache_for(self, node_id, children_ids):
503503

504504
RAM_CACHE_OLD_WORKFLOW_OOM_MULTIPLIER = 1.3
505505

506+
RAM_CACHE_LARGE_INTERMEDIATE = 512 * 1024 ** 2
507+
506508

507509
def all_outputs_dynamic(outputs):
508510
if outputs is None:
@@ -517,7 +519,6 @@ def all_outputs_dynamic(outputs):
517519

518520
return True
519521

520-
521522
class RAMPressureCache(LRUCache):
522523

523524
def __init__(self, key_class, enable_providers=False):
@@ -539,9 +540,9 @@ def set_local(self, node_id, value):
539540
self.timestamps[self.cache_key_set.get_data_key(node_id)] = time.time()
540541
super().set_local(node_id, value)
541542

542-
def ram_release(self, target, free_active=False):
543+
def ram_release(self, target, free_active=False, min_entry_size=0):
543544
if psutil.virtual_memory().available >= target:
544-
return
545+
return 0
545546

546547
clean_list = []
547548

@@ -555,28 +556,36 @@ def ram_release(self, target, free_active=False):
555556
oom_score = RAM_CACHE_OLD_WORKFLOW_OOM_MULTIPLIER ** (self.generation - self.used_generation[key])
556557

557558
ram_usage = RAM_CACHE_DEFAULT_RAM_USAGE
559+
oom_ram_usage = ram_usage
558560
def scan_list_for_ram_usage(outputs):
559-
nonlocal ram_usage
561+
nonlocal ram_usage, oom_ram_usage
560562
if outputs is None:
561563
return
562564
for output in outputs:
563565
if isinstance(output, (list, tuple)):
564566
scan_list_for_ram_usage(output)
565567
elif isinstance(output, torch.Tensor) and output.device.type == 'cpu':
566568
ram_usage += output.numel() * output.element_size()
569+
oom_ram_usage += output.numel() * output.element_size()
567570
elif isinstance(output, ModelPatcher) and self.used_generation[key] != self.generation:
568571
#old ModelPatchers are the first to go
569-
ram_usage = 1e30
572+
oom_ram_usage = 1e30
570573
scan_list_for_ram_usage(cache_entry.outputs)
571574

572-
oom_score *= ram_usage
575+
if ram_usage < min_entry_size:
576+
continue
577+
578+
oom_score *= oom_ram_usage
573579
#In the case where we have no information on the node ram usage at all,
574580
#break OOM score ties on the last touch timestamp (pure LRU)
575-
bisect.insort(clean_list, (oom_score, self.timestamps[key], key))
581+
bisect.insort(clean_list, (oom_score, self.timestamps[key], key, ram_usage))
576582

583+
freed = 0
577584
while psutil.virtual_memory().available < target and clean_list:
578-
_, _, key = clean_list.pop()
585+
_, _, key, ram_usage = clean_list.pop()
579586
del self.cache[key]
580587
self.used_generation.pop(key, None)
581588
self.timestamps.pop(key, None)
582589
self.children.pop(key, None)
590+
freed += ram_usage
591+
return freed

execution.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
HierarchicalCache,
3030
LRUCache,
3131
RAMPressureCache,
32+
RAM_CACHE_LARGE_INTERMEDIATE,
3233
)
3334
from comfy_execution.graph import (
3435
DynamicPrompt,
@@ -794,12 +795,16 @@ async def execute_async(self, prompt, prompt_id, extra_data={}, execute_outputs=
794795
if self.cache_type == CacheType.RAM_PRESSURE:
795796
ram_release_callback(ram_inactive_headroom)
796797
ram_shortfall = ram_headroom - psutil.virtual_memory().available
797-
freed = comfy.model_management.free_pins(ram_shortfall + 512 * (1024 ** 2))
798-
if freed < ram_shortfall:
799-
if freed > 64 * (1024 ** 2):
800-
# AIMDO MEM_DECOMMIT can outrun psutil.available catching up.
801-
time.sleep(0.05)
802-
ram_release_callback(ram_headroom, free_active=True)
798+
if ram_shortfall > 0:
799+
freed = ram_release_callback(ram_headroom, free_active=True, min_entry_size=RAM_CACHE_LARGE_INTERMEDIATE)
800+
ram_shortfall -= freed
801+
if comfy.model_management.should_free_pins_for_ram_pressure(ram_shortfall):
802+
freed = comfy.model_management.free_pins(ram_shortfall + 512 * (1024 ** 2))
803+
if freed < ram_shortfall:
804+
if freed > 64 * (1024 ** 2):
805+
# AIMDO MEM_DECOMMIT can outrun psutil.available catching up.
806+
time.sleep(0.05)
807+
ram_release_callback(ram_headroom, free_active=True)
803808
else:
804809
# Only execute when the while-loop ends without break
805810
# Send cached UI for intermediate output nodes that weren't executed

0 commit comments

Comments
 (0)