You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two independent JAX-on-cloud failures surfaced in the space of a week, in different repos, with different root causes, at different layers of the stack. Each was invisible until it burned hours of on-demand GPU runner time, and neither would have been predicted by "it works on a laptop" or "it works on Colab".
jax_intro kernel aborts with no traceback on every cold-cache build
confirmed by an instrumented run — three JAX kernels share one T4, the first preallocates JAX's default 75% (11.3GiB of 15.3GiB), the loser clamps to the ~3.4GiB remainder and aborts when a cell outgrows it
fixed with XLA_PYTHON_CLIENT_PREALLOCATE=false, validation run in progress
The two incidents share a pattern worth naming: our lecture code is written against a mental model of "a GPU makes JAX fast", but the runners are single inference-class GPUs (T4 on g4dn.2xlarge) shared by concurrent notebook execution, running workloads that are frequently small-matrix, float64, and latency-bound rather than throughput-bound. We do not currently have a tested model of when that combination wins, loses, or crashes — we find out one incident at a time.
Proposed project
A focused investigation to characterise JAX on our cloud CI runners and turn the findings into standing guidance and CI configuration, rather than per-incident firefighting.
Questions to answer
FP64 penalty. How large is the float64 penalty on the T4 for our actual workload shapes (Kalman filters, NUTS, small linear models)? T4 FP64 is nominally 1/32 of FP32 throughput — measure what that does to representative lecture cells, and whether jax_enable_x64 lectures should default to CPU.
Small-op / launch overhead. At what array size does the T4 break even with the runner's own CPU for our common op mix? A lax.scan of 10x10 ops may never amortise launch latency — find the crossover so lecture authors have a rule of thumb rather than a guess.
Concurrency policy. myst executes notebooks at parallelism = cpus-1, so multiple JAX kernels share one GPU. With preallocation off, what is the safe concurrency for JAX lectures, and should JAX-heavy lectures be serialised while pure-CPU lectures fan out?
Sampler configuration. Does chain_method='vectorized' close the GPU gap for numpyro workloads, or is sequential + CPU the right default for small models?
Standard CI environment. Which XLA/JAX env vars should be standard across all GPU lecture repos (XLA_PYTHON_CLIENT_PREALLOCATE, possibly XLA_PYTHON_CLIENT_MEM_FRACTION, allocator choice), and where do they belong so every repo inherits them rather than rediscovering them?
Instance fit. Is g4dn.2xlarge the right instance at all? Candidates to price against: g5/g6 (better FP64 story is not automatic — check), plain CPU instances for FP64-heavy lectures, or a split fleet where only genuinely large-array lectures get a GPU.
Failure hygiene. A pathological cell currently burns 40 minutes per builder because a failed notebook is never cached and every builder re-executes it. What per-cell timeout and caching policy makes a bad cell fail fast and fail once?
Method
A small benchmark harness that runs a matrix of representative kernels (Kalman filter scan, NUTS on the sargent_surico model, large dense linear algebra as a control, the jax_intro 50M-element ops) across {T4 GPU, runner CPU} x {float32, float64} x {1, 2, 3 concurrent processes}, with a jax profile captured for the pathological cases to separate kernel time from gap time. Run it on the actual CI runners via workflow_dispatch so the numbers are the numbers we live with. The two incident lectures become the first regression fixtures.
Deliverables
A short findings report with the measured crossover points and the answer to each question above, checked into QuantEcon/meta.
Guidance for lecture authors (a page in the style guide or manual): when to expect the GPU to help, when to pin a lecture to CPU, and the sampler/config idioms that make small models CI-safe.
An audit of existing JAX lectures against the findings: which are in the losing region (small model + x64 on GPU) and should be pinned or restructured.
Out of scope
Rewriting lecture content for performance, GPU vendor comparisons beyond what instance selection requires, and anything about the mystmd/jupyter-book build engines (tracked separately on QuantEcon/lecture-python-programming#363).
Why now
Two independent JAX-on-cloud failures surfaced in the space of a week, in different repos, with different root causes, at different layers of the stack. Each was invisible until it burned hours of on-demand GPU runner time, and neither would have been predicted by "it works on a laptop" or "it works on Colab".
jax_introkernel aborts with no traceback on every cold-cache buildXLA_PYTHON_CLIENT_PREALLOCATE=false, validation run in progressThe two incidents share a pattern worth naming: our lecture code is written against a mental model of "a GPU makes JAX fast", but the runners are single inference-class GPUs (T4 on
g4dn.2xlarge) shared by concurrent notebook execution, running workloads that are frequently small-matrix, float64, and latency-bound rather than throughput-bound. We do not currently have a tested model of when that combination wins, loses, or crashes — we find out one incident at a time.Proposed project
A focused investigation to characterise JAX on our cloud CI runners and turn the findings into standing guidance and CI configuration, rather than per-incident firefighting.
Questions to answer
jax_enable_x64lectures should default to CPU.lax.scanof 10x10 ops may never amortise launch latency — find the crossover so lecture authors have a rule of thumb rather than a guess.chain_method='vectorized'close the GPU gap for numpyro workloads, or issequential+ CPU the right default for small models?XLA_PYTHON_CLIENT_PREALLOCATE, possiblyXLA_PYTHON_CLIENT_MEM_FRACTION, allocator choice), and where do they belong so every repo inherits them rather than rediscovering them?g4dn.2xlargethe right instance at all? Candidates to price against:g5/g6(better FP64 story is not automatic — check), plain CPU instances for FP64-heavy lectures, or a split fleet where only genuinely large-array lectures get a GPU.Method
A small benchmark harness that runs a matrix of representative kernels (Kalman filter scan, NUTS on the sargent_surico model, large dense linear algebra as a control, the
jax_intro50M-element ops) across {T4 GPU, runner CPU} x {float32, float64} x {1, 2, 3 concurrent processes}, with a jax profile captured for the pathological cases to separate kernel time from gap time. Run it on the actual CI runners via workflow_dispatch so the numbers are the numbers we live with. The two incident lectures become the first regression fixtures.Deliverables
Out of scope
Rewriting lecture content for performance, GPU vendor comparisons beyond what instance selection requires, and anything about the mystmd/jupyter-book build engines (tracked separately on QuantEcon/lecture-python-programming#363).
Evidence trail
8af1015(instrumentation, engine pin) and94a7e52(fix).