Summary
On a NVIDIA GB10 (DGX Spark, aarch64) box, Jasna v0.10.0 hangs during warmup — no error, no output, just a permanent stall — after the VALI dependency moved from 4.8.7 to 4.8.8.
The hang is a deadlock when two threads construct vali.PyDecoder concurrently. Jasna creates two NvidiaVideoReader instances from different threads (jasna/pipeline_threads.py:77 in the decode/detect worker and :369 in the blend/encode worker); when both enter the vali.PyDecoder(...) constructor at the same time, they lock up in the C++ layer.
Pinning VALI back to 4.8.7 makes the hang disappear, so this looks like a regression in the VALI fork rather than in Jasna itself. I could not reproduce it on x86 — it may be timing-specific to GB10/aarch64.
Environment
|
|
| Jasna |
v0.10.0 (source build) |
| VALI |
4.8.8 (f4a67f86) — 4.8.7 (56e01a00) is fine |
| GPU / platform |
NVIDIA GB10 (DGX Spark), aarch64 |
| Driver / CUDA |
580.173.02 / CUDA 13.0 |
| Python / PyAV |
3.13 / 18.0.0 (built from PyAV main, linked against self-built FFmpeg 8.0) |
| OS |
Ubuntu 24.04, kernel 6.17.0-1029-nvidia |
Symptoms
Warmup starts and then never finishes. Observed with py-spy dump:
- both the decode/detect and the blend/encode thread sit on the
vali.PyDecoder(...) constructor line for 20s+, not moving
- all 66 threads
sleeping
- CPU ~1.5%, GPU 0%, no network activity
So it is a genuine deadlock, not slow work.
Evidence that it is VALI 4.8.8, not Jasna
- Backend swap —
JASNA_DECODE_BACKEND=pyav-hw with otherwise identical arguments completes 100% of the time (77.3 fps). Only the VALI path hangs.
- Version bisect — VALI 4.8.7 never showed this. The two-reader structure in Jasna has not changed since v0.9.1, so the variable is the VALI bump.
- Likely culprit — the only new locking between 4.8.7 and 4.8.8 is in
d14a25b "fix(decode): retry pending packet", which adds std::unique_lock lock{m_mutex} in has_pending() in src/TC/src/TaskDecodeFrame.cpp. My guess is that this new mutex can be taken while another decoder is still initialising, and crosses with an existing lock during concurrent construction. I have not verified that interleaving in a debugger, so please treat the exact mechanism as a hypothesis — the reproducible facts are the three points above.
(The other 4.8.8 commit, 3ad0d54 "tolerate corrupt packets during decode", adds DecodeSingleSurfaceAsyncDetailed and does not introduce locks.)
Workaround currently in use
Serialising decoder construction with a module-level lock is enough — construction is only milliseconds, so serialising it costs nothing, and decoding afterwards is unaffected:
_VALI_DECODER_INIT_LOCK = threading.Lock()
with _VALI_DECODER_INIT_LOCK:
self.decoder = vali.PyDecoder(
file, {}, gpu_id=device.index or 0, stream=self.stream.cuda_stream
)
With this in place the VALI path completes reliably at 80.7 fps — faster than the pyav-hw fallback (77.3 fps), which is why keeping VALI is worthwhile.
Happy to run any additional diagnostics on the GB10 box (gdb/py-spy traces, patched VALI builds) if that helps narrow it down.
Summary
On a NVIDIA GB10 (DGX Spark, aarch64) box, Jasna v0.10.0 hangs during warmup — no error, no output, just a permanent stall — after the VALI dependency moved from 4.8.7 to 4.8.8.
The hang is a deadlock when two threads construct
vali.PyDecoderconcurrently. Jasna creates twoNvidiaVideoReaderinstances from different threads (jasna/pipeline_threads.py:77in the decode/detect worker and:369in the blend/encode worker); when both enter thevali.PyDecoder(...)constructor at the same time, they lock up in the C++ layer.Pinning VALI back to 4.8.7 makes the hang disappear, so this looks like a regression in the VALI fork rather than in Jasna itself. I could not reproduce it on x86 — it may be timing-specific to GB10/aarch64.
Environment
f4a67f86) — 4.8.7 (56e01a00) is fineSymptoms
Warmup starts and then never finishes. Observed with
py-spy dump:vali.PyDecoder(...)constructor line for 20s+, not movingsleepingSo it is a genuine deadlock, not slow work.
Evidence that it is VALI 4.8.8, not Jasna
JASNA_DECODE_BACKEND=pyav-hwwith otherwise identical arguments completes 100% of the time (77.3 fps). Only the VALI path hangs.d14a25b"fix(decode): retry pending packet", which addsstd::unique_lock lock{m_mutex}inhas_pending()insrc/TC/src/TaskDecodeFrame.cpp. My guess is that this new mutex can be taken while another decoder is still initialising, and crosses with an existing lock during concurrent construction. I have not verified that interleaving in a debugger, so please treat the exact mechanism as a hypothesis — the reproducible facts are the three points above.(The other 4.8.8 commit,
3ad0d54"tolerate corrupt packets during decode", addsDecodeSingleSurfaceAsyncDetailedand does not introduce locks.)Workaround currently in use
Serialising decoder construction with a module-level lock is enough — construction is only milliseconds, so serialising it costs nothing, and decoding afterwards is unaffected:
With this in place the VALI path completes reliably at 80.7 fps — faster than the
pyav-hwfallback (77.3 fps), which is why keeping VALI is worthwhile.Happy to run any additional diagnostics on the GB10 box (gdb/py-spy traces, patched VALI builds) if that helps narrow it down.