From 8084083d4b085e0ba4bf09b31a050e48ea2a970a Mon Sep 17 00:00:00 2001 From: rattus <46076784+rattus128@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:55:37 +1000 Subject: [PATCH 1/3] comfy-aimdo 0.4.11 (#15215) Changes: Remove sequential scan hint Prefer NVML pressure on windows Add async malloc clamp option (unused by comfy so far) Workaround AMD windows GPU virtual address space leak The largest change is the NVML pressure, which works around a cuMemGetInfo drift from actual VRAM in some circumstances. --- comfy/cli_args.py | 1 + main.py | 11 ++++++++--- requirements.txt | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/comfy/cli_args.py b/comfy/cli_args.py index 792148f0ab3..ee9e1ce9f1a 100644 --- a/comfy/cli_args.py +++ b/comfy/cli_args.py @@ -172,6 +172,7 @@ def from_string(cls, value: str): parser.add_argument("--reserve-vram", type=float, default=None, help="Set the amount of vram in GB you want to reserve for use by your OS/other software. By default some amount is reserved depending on your OS.") parser.add_argument("--vram-headroom", type=float, default=0, help="Set the amount of vram in GB for DynamicVRAM to maintain as extra headroom above default. ComfyUI will try and keep this much VRAM completely free and unused, even counting VRAM from other apps.") +parser.add_argument("--disable-nvml-pressure", action="store_true", help="Use CUDA instead of NVML for DynamicVRAM memory pressure.") parser.add_argument("--async-offload", nargs='?', const=2, type=int, default=None, metavar="NUM_STREAMS", help="Use async weight offloading. An optional argument controls the amount of offload streams. Default is 2. Enabled by default on Nvidia.") parser.add_argument("--disable-async-offload", action="store_true", help="Disable async weight offloading.") diff --git a/main.py b/main.py index 9c318fafe76..361b1fc899a 100644 --- a/main.py +++ b/main.py @@ -58,11 +58,16 @@ def dump_traceback_on_sigint(signum, frame): import comfy_aimdo.control if enables_dynamic_vram(): + simple_vram_headroom = None if args.reserve_vram is None else int(args.reserve_vram * 1024 ** 3) try: - comfy_aimdo.control.init(simple_vram_headroom=None if args.reserve_vram is None else int(args.reserve_vram * 1024 ** 3)) + comfy_aimdo.control.init(simple_vram_headroom=simple_vram_headroom, nvml_pressure=not args.disable_nvml_pressure) except TypeError: - # comfy-aimdo 0.4.9 protocol. - comfy_aimdo.control.init() + # comfy-aimdo 0.4.10 protocol. + try: + comfy_aimdo.control.init(simple_vram_headroom=simple_vram_headroom) + except TypeError: + # comfy-aimdo 0.4.9 protocol. + comfy_aimdo.control.init() if os.name == "nt": os.environ['MIMALLOC_PURGE_DELAY'] = '0' diff --git a/requirements.txt b/requirements.txt index aa3fbba8e4c..c1eeb975241 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ SQLAlchemy>=2.0.0 filelock av>=16.0.0 comfy-kitchen==0.2.26 -comfy-aimdo==0.4.10 +comfy-aimdo==0.4.11 requests simpleeval>=1.0.0 blake3 From 364081170f1c15853608db1f24ed9897763bdd09 Mon Sep 17 00:00:00 2001 From: Alexander Piskun <13381981+bigcat88@users.noreply.github.com> Date: Sun, 2 Aug 2026 17:10:47 +0300 Subject: [PATCH 2/3] [Partner Nodes] feat(Minimax): add 768P resolution for H3 model (#15227) Signed-off-by: Alexander Piskun --- comfy_api_nodes/nodes_minimax.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/comfy_api_nodes/nodes_minimax.py b/comfy_api_nodes/nodes_minimax.py index 2d7aef6548f..3c1d2925798 100644 --- a/comfy_api_nodes/nodes_minimax.py +++ b/comfy_api_nodes/nodes_minimax.py @@ -467,7 +467,7 @@ def _hailuo03_model_inputs(include_ratio: bool = True, allow_adaptive: bool = Tr ), IO.Combo.Input( "resolution", - options=["2K"], + options=["768P", "2K"], tooltip="Resolution of the output video.", ), ] @@ -578,11 +578,12 @@ def define_schema(cls): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["model.duration"]), + depends_on=IO.PriceBadgeDepends(widgets=["model.resolution", "model.duration"]), expr=""" ( $dur := $lookup(widgets, "model.duration"); - {"type": "usd", "usd": $dur * 0.1859} + $rate := $lookup(widgets, "model.resolution") = "768p" ? 0.1287 : 0.1859; + {"type": "usd", "usd": $dur * $rate} ) """, ), @@ -660,11 +661,12 @@ def define_schema(cls): ], is_api_node=True, price_badge=IO.PriceBadge( - depends_on=IO.PriceBadgeDepends(widgets=["model.duration"]), + depends_on=IO.PriceBadgeDepends(widgets=["model.resolution", "model.duration"]), expr=""" ( $dur := $lookup(widgets, "model.duration"); - {"type": "usd", "usd": $dur * 0.1859} + $rate := $lookup(widgets, "model.resolution") = "768p" ? 0.1287 : 0.1859; + {"type": "usd", "usd": $dur * $rate} ) """, ), @@ -818,20 +820,21 @@ def define_schema(cls): is_api_node=True, price_badge=IO.PriceBadge( depends_on=IO.PriceBadgeDepends( - widgets=["model.duration"], + widgets=["model.resolution", "model.duration"], input_groups=["model.reference_images", "model.reference_videos"], ), expr=""" ( $dur := $lookup(widgets, "model.duration"); + $rate := $lookup(widgets, "model.resolution") = "768p" ? 0.1287 : 0.1859; $imgsRaw := $lookup(inputGroups, "model.reference_images"); $imgs := $imgsRaw ? $imgsRaw : 0; $vidsRaw := $lookup(inputGroups, "model.reference_videos"); $vids := $vidsRaw ? $vidsRaw : 0; - $base := $dur * 0.1859 + ($imgs > 5 ? ($imgs - 5) * 0.0572 : 0); + $base := $dur * $rate + ($imgs > 5 ? ($imgs - 5) * 0.0572 : 0); $vids > 0 - ? {"type": "range_usd", "min_usd": $base + $vids * 2 * 0.1859, - "max_usd": $base + 15 * 0.1859, "format": {"approximate": true}} + ? {"type": "range_usd", "min_usd": $base + $vids * 2 * $rate, + "max_usd": $base + 15 * $rate, "format": {"approximate": true}} : {"type": "usd", "usd": $base} ) """, From 611f2a4e0f30ea7f50451fd34ab25b8f9365ff2f Mon Sep 17 00:00:00 2001 From: rattus <46076784+rattus128@users.noreply.github.com> Date: Mon, 3 Aug 2026 01:16:06 +1000 Subject: [PATCH 3/3] fix pin registration priority (#15226) This priority scheme was broken in the case where you have pin registration exhaustion while loading a VBAR that gets a big evicition. The weight would stay in the loaded set but inherit the MRU priority against other workflow models WRT pin registration which leads to async offload without pinning. Fix by universally promiting active pin registration above workflow pins without concern for the weights/weights-loaded split. This diverges from the actual budgeting where the split still makes sense. --- comfy/model_management.py | 21 +++++++++++++++++---- comfy/pinned_memory.py | 6 +++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/comfy/model_management.py b/comfy/model_management.py index e3c94c15a34..1000f69e15d 100644 --- a/comfy/model_management.py +++ b/comfy/model_management.py @@ -671,6 +671,19 @@ def pin_eviction_tiers(loaded, evict_active): tiers.append((PIN_SUBSETS, True, True)) return tiers +def registration_eviction_tiers(evict_active): + subsets = PIN_SUBSETS + LOADED_PIN_SUBSETS + tiers = [ + (subsets, False, False), + (subsets, True, False), + ] + if evict_active: + tiers.extend([ + (subsets, False, True), + (subsets, True, True), + ]) + return tiers + def free_pins(size, evict_active=False, loaded=False): freed = 0 for subsets, current_prompt, active in pin_eviction_tiers(loaded, evict_active): @@ -703,19 +716,19 @@ def ensure_pin_budget(size, evict_active=False, loaded=False): to_free = shortfall + PIN_PRESSURE_HYSTERESIS return free_pins(to_free, evict_active=evict_active, loaded=loaded) >= shortfall -def free_registrations(shortfall, evict_active=True, loaded=False): +def free_registrations(shortfall, evict_active=True): if MAX_PINNED_MEMORY <= 0: return False if shortfall <= 0: return True shortfall += REGISTERABLE_PIN_HYSTERESIS - for subsets, current_prompt, active in pin_eviction_tiers(loaded, evict_active): + for subsets, current_prompt, active in registration_eviction_tiers(evict_active): shortfall -= free_model_pins(shortfall, subsets, current_prompt, active, registrations=True) return shortfall <= REGISTERABLE_PIN_HYSTERESIS -def ensure_pin_registerable(size, evict_active=True, loaded=False): - return free_registrations(TOTAL_PINNED_MEMORY + size - MAX_PINNED_MEMORY, evict_active=evict_active, loaded=loaded) +def ensure_pin_registerable(size, evict_active=True): + return free_registrations(TOTAL_PINNED_MEMORY + size - MAX_PINNED_MEMORY, evict_active=evict_active) class LoadedModel: def __init__(self, model: ModelPatcher): diff --git a/comfy/pinned_memory.py b/comfy/pinned_memory.py index d78ab3c76a9..e9a9a70e298 100644 --- a/comfy/pinned_memory.py +++ b/comfy/pinned_memory.py @@ -56,7 +56,7 @@ def get_pin(module, subset="weights"): _, _, stack_split, pinned_size, *_ = module._pin_state[subset] size = pin.nbytes - comfy.model_management.ensure_pin_registerable(size, loaded=subset.endswith("-loaded")) + comfy.model_management.ensure_pin_registerable(size) if torch.cuda.cudart().cudaHostRegister(pin.data_ptr(), size, 1) != 0: comfy.model_management.discard_cuda_async_error() @@ -93,7 +93,7 @@ def pin_memory(module, subset="weights", size=None): comfy.memory_management.extra_ram_release(comfy.memory_management.RAM_CACHE_HEADROOM) if (not comfy.model_management.ensure_pin_budget(size, loaded=loaded) or - not comfy.model_management.ensure_pin_registerable(registerable_size, loaded=loaded)): + not comfy.model_management.ensure_pin_registerable(registerable_size)): return _steal_pin(module, stack, buckets, size, priority, subset) offset = hostbuf.size @@ -105,7 +105,7 @@ def pin_memory(module, subset="weights", size=None): pin.untyped_storage()._comfy_hostbuf = hostbuf if torch.cuda.cudart().cudaHostRegister(pin.data_ptr(), size, 1) != 0: comfy.model_management.discard_cuda_async_error() - comfy.model_management.free_registrations(size, loaded=loaded) + comfy.model_management.free_registrations(size) if torch.cuda.cudart().cudaHostRegister(pin.data_ptr(), size, 1) != 0: comfy.model_management.discard_cuda_async_error() del pin