@user9208212 — task for your Claude, on the 8 GB NVIDIA box.
Context
#24 and #25 fix a chronic torch allocator gc gate: under
backend:native the allocated/reserved ratio gate (0.95) is always
exceeded, so the R gc callback fired on nearly every CUDA allocation —
up to ~90% of image-generation wall time was R gc. The fix (see
.flux_gc_gates() in R/memory_flux.R) disables the ratio gate and
uses an absolute allocated_rate gate at 0.65 of total VRAM plus a
footprint-based reserved net. Measured wins on a 16 GB RTX 5060 Ti at
1024px: Z-Image 143→24 s, FLUX.2 klein 48→13 s, SDXL 234→100 s,
SD 2.1 (768px) 101→26 s.
All constants are tuned on 16 GB. On 8 GB the sizing may be wrong in
both directions:
allocated_rate 0.65 = 5.2 GB, which is likely below the live
working set for SDXL (unet fp16 alone is ~5 GB) — the gate could turn
chronic again and the win could vanish.
- With fewer gcs, garbage rides higher between collections: we saw the
SD21 sawtooth peak at 13.3 GB where the baseline sat at 5.4 GB. That
headroom does not exist on 8 GB — OOM is a real possibility.
The task
- Install the branch:
remotes::install_github("cornball-ai/diffuseR@feature/sd-gc-gates")
- For each model that fits, run one warm generation per arm with the
script below: GATES=0 pins the old torch defaults (a true baseline
through the same code path); GATES=1 uses the new gates.
- SD 2.1, 768px (core ask — fits comfortably)
- FLUX.2 klein fp8, 512px and 1024px if you have the
cornball safetensors fork (remotes::install_github("cornball-ai/safetensors");
needed for the float8 dtype) — pass text_device = "cpu" to
flux2_load_pipeline(), the Qwen3 encoder won't fit on 8 GB
- SDXL, 768px optional,
decoder = "cpu"; skip if it OOMs
- If
GATES=1 OOMs where GATES=0 doesn't, retry with a smaller
absolute gate before the library loads, e.g.
options(torch.cuda_allocator_allocated_rate = 0.5) — finding the
right 8 GB sizing is the point of this task.
# GATES=0 baseline / GATES=1 new gates; PIPE=sd21 (or sdxl)
library(diffuseR)
if (Sys.getenv("GATES") == "0") {
options(torch.cuda_allocator_allocated_reserved_rate = 0.8)
options(torch.cuda_allocator_allocated_rate = 0.8)
options(torch.cuda_allocator_reserved_rate = 0.2)
}
options(timeout = 1800)
torch::local_no_grad()
PROMPT <- "A retro 1970s radio station studio interior, warm wood panels, vinyl records on the walls, soft neon glow, detailed illustration"
devices <- list(unet = "cuda", decoder = "cpu",
text_encoder = "cuda", encoder = "cpu")
m2d <- models2devices("sd21", devices = devices,
unet_dtype_str = "float16", download_models = TRUE)
pipeline <- load_pipeline("sd21", m2d = m2d, unet_dtype_str = "float16",
use_native_unet = TRUE, use_native_decoder = TRUE,
use_native_text_encoder = TRUE)
gen <- function(seed) {
g0 <- gc.time()
tw <- system.time(
txt2img_sd21(PROMPT, pipeline = pipeline, devices = devices,
img_dim = 768, num_inference_steps = 50,
guidance_scale = 7.5, seed = seed,
use_native_unet = TRUE, use_native_decoder = TRUE,
use_native_text_encoder = TRUE,
save_file = FALSE, verbose = FALSE)
)
g1 <- gc.time()
gc(FALSE); torch::cuda_empty_cache()
c(wall = tw[["elapsed"]], gc = g1[3] - g0[3])
}
invisible(gen(1L)) # warmup
r <- gen(42L)
ms <- torch::cuda_memory_stats()
cat(sprintf("gates=%s: %.1f s (gc %.1f s), peak %.2f GB alloc / %.2f GB reserved\n",
Sys.getenv("GATES"), r[["wall"]], r[["gc"]],
ms$allocated_bytes$all$peak / 1e9,
ms$reserved_bytes$all$peak / 1e9))
Report back (in this issue)
Per model × arm: warm wall seconds, gc seconds, peak alloc/reserved,
OOM yes/no — plus the GPU model, driver version, and
packageVersion("torch"). If you find a gate sizing that works better
on 8 GB, include it; we'll fold it into .flux_gc_gates() as a
VRAM-aware default.
@user9208212 — task for your Claude, on the 8 GB NVIDIA box.
Context
#24 and #25 fix a chronic torch allocator gc gate: under
backend:nativethe allocated/reserved ratio gate (0.95) is alwaysexceeded, so the R gc callback fired on nearly every CUDA allocation —
up to ~90% of image-generation wall time was R gc. The fix (see
.flux_gc_gates()inR/memory_flux.R) disables the ratio gate anduses an absolute
allocated_rategate at 0.65 of total VRAM plus afootprint-based reserved net. Measured wins on a 16 GB RTX 5060 Ti at
1024px: Z-Image 143→24 s, FLUX.2 klein 48→13 s, SDXL 234→100 s,
SD 2.1 (768px) 101→26 s.
All constants are tuned on 16 GB. On 8 GB the sizing may be wrong in
both directions:
allocated_rate0.65 = 5.2 GB, which is likely below the liveworking set for SDXL (unet fp16 alone is ~5 GB) — the gate could turn
chronic again and the win could vanish.
SD21 sawtooth peak at 13.3 GB where the baseline sat at 5.4 GB. That
headroom does not exist on 8 GB — OOM is a real possibility.
The task
script below:
GATES=0pins the old torch defaults (a true baselinethrough the same code path);
GATES=1uses the new gates.cornball safetensors fork (
remotes::install_github("cornball-ai/safetensors");needed for the float8 dtype) — pass
text_device = "cpu"toflux2_load_pipeline(), the Qwen3 encoder won't fit on 8 GBdecoder = "cpu"; skip if it OOMsGATES=1OOMs whereGATES=0doesn't, retry with a smallerabsolute gate before the library loads, e.g.
options(torch.cuda_allocator_allocated_rate = 0.5)— finding theright 8 GB sizing is the point of this task.
Report back (in this issue)
Per model × arm: warm wall seconds, gc seconds, peak alloc/reserved,
OOM yes/no — plus the GPU model, driver version, and
packageVersion("torch"). If you find a gate sizing that works betteron 8 GB, include it; we'll fold it into
.flux_gc_gates()as aVRAM-aware default.