saliacoel commited on
Commit
6d8ebaf
·
verified ·
1 Parent(s): 0fa6520

Upload salia_maxVRAMpurge.py

Browse files
Files changed (1) hide show
  1. salia_maxVRAMpurge.py +233 -0
salia_maxVRAMpurge.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import fnmatch
4
+ import gc
5
+ from typing import Any
6
+
7
+ import torch
8
+ import comfy.model_management as mm
9
+
10
+
11
+ class AnyType(str):
12
+ """Wildcard type helper for ComfyUI type checks."""
13
+
14
+ def __ne__(self, __value: object) -> bool:
15
+ return False
16
+
17
+
18
+ any_type = AnyType("*")
19
+
20
+
21
+ # -----------------------------------------------------------------------------
22
+ # Verified behavior from LayerStyle: Purge VRAM V2
23
+ # purge_vram_v2(...):
24
+ # clear_memory()
25
+ # unload_all_models()
26
+ # soft_empty_cache()
27
+ # return (anything,)
28
+ #
29
+ # Verified clear_memory() from LayerStyle/imagefunc.py:
30
+ # gc.collect()
31
+ # if torch.cuda.is_available():
32
+ # torch.cuda.empty_cache()
33
+ # torch.cuda.ipc_collect()
34
+ # -----------------------------------------------------------------------------
35
+ def _layerstyle_clear_memory() -> None:
36
+ gc.collect()
37
+ try:
38
+ if torch.cuda.is_available():
39
+ torch.cuda.empty_cache()
40
+ torch.cuda.ipc_collect()
41
+ except Exception:
42
+ pass
43
+
44
+
45
+ def _run_layerstyle_purge_v2() -> None:
46
+ _layerstyle_clear_memory()
47
+
48
+ if hasattr(mm, "unload_all_models"):
49
+ try:
50
+ mm.unload_all_models()
51
+ except Exception:
52
+ pass
53
+
54
+ if hasattr(mm, "soft_empty_cache"):
55
+ try:
56
+ mm.soft_empty_cache()
57
+ except TypeError:
58
+ try:
59
+ mm.soft_empty_cache(False)
60
+ except Exception:
61
+ pass
62
+ except Exception:
63
+ pass
64
+
65
+
66
+ # -----------------------------------------------------------------------------
67
+ # Verified behavior from comfyui-unload-model: UnloadAllModels
68
+ # route(...):
69
+ # unload_all_models()
70
+ # soft_empty_cache(True)
71
+ # gc.collect()
72
+ # torch.cuda.empty_cache()
73
+ # torch.cuda.ipc_collect()
74
+ # return (value,)
75
+ # -----------------------------------------------------------------------------
76
+ def _run_unload_all_models_pack() -> None:
77
+ if hasattr(mm, "unload_all_models"):
78
+ try:
79
+ mm.unload_all_models()
80
+ except Exception:
81
+ pass
82
+
83
+ if hasattr(mm, "soft_empty_cache"):
84
+ try:
85
+ mm.soft_empty_cache(True)
86
+ except TypeError:
87
+ try:
88
+ mm.soft_empty_cache(force=True)
89
+ except Exception:
90
+ try:
91
+ mm.soft_empty_cache()
92
+ except Exception:
93
+ pass
94
+ except Exception:
95
+ pass
96
+
97
+ gc.collect()
98
+
99
+ try:
100
+ if torch.cuda.is_available():
101
+ torch.cuda.empty_cache()
102
+ torch.cuda.ipc_collect()
103
+ except Exception:
104
+ pass
105
+
106
+
107
+ # -----------------------------------------------------------------------------
108
+ # Missing behavior from the provided easy cleanGpuUsed replacement:
109
+ # remove_cache('*')
110
+ # This is NOT present in the two researched nodes, so we add it here.
111
+ # -----------------------------------------------------------------------------
112
+ def remove_cache(cache_key: str = "*") -> None:
113
+ """Best-effort backend cache clearing for varying ComfyUI versions."""
114
+ pattern = cache_key or "*"
115
+
116
+ def _clear_dict(d: dict) -> None:
117
+ if pattern == "*":
118
+ d.clear()
119
+ return
120
+ for k in list(d.keys()):
121
+ if fnmatch.fnmatch(str(k), pattern):
122
+ d.pop(k, None)
123
+
124
+ def _clear_known_cache_dicts(obj: Any) -> None:
125
+ if obj is None:
126
+ return
127
+
128
+ interesting_names = {
129
+ "cache",
130
+ "caches",
131
+ "output_cache",
132
+ "outputs",
133
+ "outputs_ui",
134
+ "history",
135
+ "prompt_cache",
136
+ }
137
+
138
+ for name in dir(obj):
139
+ if name.startswith("_"):
140
+ continue
141
+
142
+ lname = name.lower()
143
+ if lname in {"queue", "task_queue", "tasks", "prompt_queue"}:
144
+ continue
145
+
146
+ if (lname in interesting_names) or ("cache" in lname):
147
+ try:
148
+ val = getattr(obj, name, None)
149
+ except Exception:
150
+ continue
151
+ if isinstance(val, dict):
152
+ _clear_dict(val)
153
+
154
+ try:
155
+ import server
156
+
157
+ ps_cls = getattr(server, "PromptServer", None)
158
+ ps_inst = getattr(ps_cls, "instance", None) if ps_cls is not None else None
159
+ ps = ps_inst() if callable(ps_inst) else ps_inst
160
+
161
+ pq = getattr(ps, "prompt_queue", None) if ps is not None else None
162
+ _clear_known_cache_dicts(pq)
163
+ _clear_known_cache_dicts(getattr(pq, "executor", None))
164
+ _clear_known_cache_dicts(getattr(ps, "executor", None))
165
+ _clear_known_cache_dicts(getattr(ps, "prompt_executor", None))
166
+ except Exception:
167
+ pass
168
+
169
+ try:
170
+ import comfy_execution.caching as caching # type: ignore
171
+
172
+ _clear_known_cache_dicts(caching)
173
+
174
+ for attr in ("CACHE", "CACHES", "cache", "caches"):
175
+ d = getattr(caching, attr, None)
176
+ if isinstance(d, dict):
177
+ _clear_dict(d)
178
+
179
+ for func_name in ("clear_cache", "clear_caches", "clear_all", "clear"):
180
+ fn = getattr(caching, func_name, None)
181
+ if callable(fn):
182
+ try:
183
+ try:
184
+ fn(pattern)
185
+ except TypeError:
186
+ fn()
187
+ except Exception:
188
+ pass
189
+ except Exception:
190
+ pass
191
+
192
+ gc.collect()
193
+
194
+
195
+ class Salia_Maximum_VRAM_Purge:
196
+ @classmethod
197
+ def INPUT_TYPES(cls):
198
+ return {
199
+ "required": {"anything": (any_type, {})},
200
+ "optional": {},
201
+ "hidden": {"unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO"},
202
+ }
203
+
204
+ RETURN_TYPES = (any_type,)
205
+ RETURN_NAMES = ("any",)
206
+ OUTPUT_NODE = True
207
+ FUNCTION = "maximum_purge"
208
+ CATEGORY = "System/Memory"
209
+
210
+ @classmethod
211
+ def IS_CHANGED(cls, **kwargs):
212
+ return float("nan")
213
+
214
+ def maximum_purge(self, anything, unique_id=None, extra_pnginfo=None):
215
+ # 1) Run the verified LayerStyle Purge VRAM V2 behavior.
216
+ _run_layerstyle_purge_v2()
217
+
218
+ # 2) Run the verified comfyui-unload-model UnloadAllModels behavior.
219
+ _run_unload_all_models_pack()
220
+
221
+ # 3) Add only the missing easy cleanGpuUsed part that the two nodes do not do.
222
+ remove_cache("*")
223
+
224
+ return (anything,)
225
+
226
+
227
+ NODE_CLASS_MAPPINGS = {
228
+ "Salia_Maximum_VRAM_Purge": Salia_Maximum_VRAM_Purge,
229
+ }
230
+
231
+ NODE_DISPLAY_NAME_MAPPINGS = {
232
+ "Salia_Maximum_VRAM_Purge": "Salia_Maximum_VRAM_Purge",
233
+ }