Part of #925 (Phase 1). Measure first: the Phase 0 deployment (#928) includes cold/warm import-time benchmarks — if warm import lands under a couple of seconds, deprioritise this issue.
Problem
import quantecon triggers eager Numba compilation of five callables:
Natively this costs milliseconds and nobody notices. In the browser, each eager compile is a full LLVM optimisation + WASM object emission + in-process LLD link + side-module load, and the emscripten-forge patches force-disable cache=True for @guvectorize/@vectorize — so the four gufunc compiles are not amortised by the persistent cache and are paid every session, on the critical path of every notebook. (comb_jit is an ordinary dispatcher with cache=True, so it does benefit from the cache after the first session.)
Options, in increasing order of ambition
- Convert the eagerly-signed gufuncs to lazy compilation — drop the explicit signature lists (dynamic gufuncs), or construct the parallel/cpu variants on first use inside
probvec.
- Replace the small gufuncs with
@njit(cache=True) loop implementations exposed through @overload — converts them from never-cached to persistently cached on Emscripten.
- Defer heavy submodule imports in
quantecon/__init__.py via module __getattr__ (PEP 562) — also improves native import time.
Acceptance criteria
Part of #925 (Phase 1). Measure first: the Phase 0 deployment (#928) includes cold/warm import-time benchmarks — if warm import lands under a couple of seconds, deprioritise this issue.
Problem
import quantecontriggers eager Numba compilation of five callables:_probvec_parallelguvectorizewith explicit signature_probvec_cpusample_without_replacementgufunc_ints_arr_to_bitscomb_jit@jitsignatureintp(intp, intp)Natively this costs milliseconds and nobody notices. In the browser, each eager compile is a full LLVM optimisation + WASM object emission + in-process LLD link + side-module load, and the emscripten-forge patches force-disable
cache=Truefor@guvectorize/@vectorize— so the four gufunc compiles are not amortised by the persistent cache and are paid every session, on the critical path of every notebook. (comb_jitis an ordinary dispatcher withcache=True, so it does benefit from the cache after the first session.)Options, in increasing order of ambition
probvec.@njit(cache=True)loop implementations exposed through@overload— converts them from never-cached to persistently cached on Emscripten.quantecon/__init__.pyvia module__getattr__(PEP 562) — also improves native import time.Acceptance criteria
import quantecontime in JupyterLite measured before and after; result recorded hereqe.random.probvec(..., parallel=...)keeps its signature)