Đêm trước đó, render pipeline của lab gặp hiện tượng kỳ lạ tốn rất nhiều thời gian: job flux trên GPU1 (RTX 5060 Ti 16GB) mất hơn 2 phút mỗi step, trong khi cùng job đó trên GPU0 (card cùng model) hoàn thành cả batch trong ~54 giây. Chúng tôi test lại 3 lần — không phải ngẫu nhiên.

Đọc signature cho đúng trước

Việc đầu tiên tôi làm là lấy mẫu nvidia-smi trong lúc job treo, 6 lần. Kết quả cho ra signature nói lên tất cả:

Giá trị khi job treo Đo được
SM utilization 96–99% (trông như "đang làm việc nặng")
Memory utilization 0–1% (không có data transfer nào)
Công suất card 38W (thấp bất thường cho sampling)
Thời gian mỗi step >120 giây (bình thường ~4 giây)

SM đầy nhưng memory bằng 0 + công suất thấp = card không thực sự tính toán, nó đang spin-wait. Đây là livelock của runtime, không phải load của model. So với job bình thường có signature thực sự là sm 96–99% + mem-util 18–41% + công suất 115–143W.

Chỉ có một biến thay đổi thực sự

GPU0 và GPU1 dùng cùng model card, cùng model (flux1-dev fp8), nhưng khác runtime:

  • GPU0 (:8188) — imgfactory python_embeded, torch 2.7.1+cu128
  • GPU1 (:8190) — venv Python 3.12, torch 2.13.0+cu130

Giả thuyết duy nhất đêm đó: runtime 2.7.1+cu128 không tương thích với kiến trúc Blackwell của 5060 Ti trong workload dequant nặng. Cách chứng minh không khó — lấy runtime đã được kiểm chứng của GPU0 chạy trên GPU1 qua CUDA_VISIBLE_DEVICES=1, không động vào model hay workload.

Kết quả sau khi chuyển runtime

Sau khi chuyển sang start_gpu1_v2 (imgfactory python_embeded, torch 2.13.0+cu130, tách riêng output/input/db directory để tránh xung đột với 8188):

Gate Kết quả
Job đơn (job 85917) 54.4 giây — trở lại bình thường
8 job liên tiếp 50.7–127.4 giây, pass hết
10 job tổng 10/10 PASS · median 54.15 giây
So với GPU0 cùng thời điểm parity 100.3% (band ±50%)
Tác động phụ lên GPU0 Không — 8188 vẫn chạy và publish ảnh trong cùng khoảng thời gian

Throughput thực tế đo được của GPU1 sau khi fix = 30.5 job/giờ (10 job / 1,182 giây).

Những gì chúng tôi không làm (và không nên làm)

  • Không xóa venv cũ — để lại ở E:\ComfyUI theo quy tắc "chuyển không xóa", chỉ đổi schtask trỏ sang launcher mới.
  • Không động vào idle_watchdog cũ từng giúp reboot khi sinh ra bản sao — đã tháo ra, xử lý bằng cách heal thủ công khi cần.
  • Không động vào bất kỳ thứ gì khác: workload, tham số, model, thứ tự queue — tất cả giữ nguyên byte-by-byte.

Bài học của lab

Khi gặp GPU "chậm", đừng vội đổ lỗi cho model hay tăng VRAM — luôn đọc ba giá trị này trước: SM, memory utilization, và watt. Nếu sm đầy nhưng memory bằng 0, vấn đề gần như chắc chắn ở runtime. Và cách chứng minh đúng là thay đổi một biến duy nhất (runtime), giữ nguyên mọi thứ khác, rồi đo 10 job — không phải đoán rồi đi tìm driver mới ngay từ đầu.