The warm session — GPU solves without the per-run startup

The first call costs minutes on a GPU: Julia boots, the CUDA stack loads, the device initializes, and the solver’s kernels compile — several minutes on a typical box, paid again by every fresh process. The model cache removes that price for CPU models by compiling them to shared libraries; device code cannot be cached that way.

The warm session removes it by keeping one process alive. In a terminal (or a tmux pane):

$ madsuite
madsuite: warm session on /run/user/1001/madsuite/daemon.sock (C-c to close)

and every script on the machine now dispatches to it, unchanged:

$ python mymodel.py     # seconds, not minutes

Measured on one machine (AC OPF, pglib case1354_pegase, backend="cuda", client always a fresh process):

no daemon: cold run to first solution

308 s

daemon running: same script

~6 s (a replay + solve)

the same process solving again (a sweep, new data)

~0.7 s

What actually happens

Your script never leaves your process — your environment, your debugger, your prints all behave normally. While a session is reachable, Core(...) records the model instead of building it (pure Python, milliseconds), and Model(core) ships the recording to the session, which replays it through the ordinary eager path and keeps the built model live for as long as your process holds it. Solves send parameter values and return solution arrays; set_parameters sweeps hit the live model at bare solve cost.

With no session running, nothing changes at all: the same script builds eagerly in-process, exactly as this manual describes everywhere else. Every failure — the session going down mid-run, a version mismatch after an upgrade — falls back to the in-process path silently and correctly. A model a recording cannot carry (a Python-callback oracle) simply builds eagerly and skips the session.

Lifetime: models die with your process

The session holds a model only while some client process holds it — exit, crash, or drop the Model object, and the session destroys the built model, runs the garbage collector, and releases device memory. Several processes using the same model share one live instance until the last of them leaves. What survives across clients is compilation only: Julia’s compiled kernels (which is why the second-ever client of a model family builds in seconds, not minutes) and the model cache’s libraries — a cache=True model that misses is compiled and stored by the session as a side effect.

Controls

$ madsuite status
pid 12345, up 2h03m, 41 solves (0 errors), 0 queued, 2 clients, ...
$ madsuite stop
  • MADSUITE_DAEMON=0 — this process never dispatches.

  • MADSUITE_DAEMON=/path/to.sock — dispatch there instead of the default ($XDG_RUNTIME_DIR/madsuite/daemon.sock).

  • madsuite --max-instances N — live models kept before the least recently used is dropped (a dropped model rebuilds transparently on next use).

  • madsuite --idle-exit MINUTES — exit after that long with no clients and no work. Julia never unloads compiled code, so a long-lived session only grows; an occasional fresh start is the reset.

Limits, honestly

  • Solves are served one at a time, first come first served; status shows the queue. (The session stays responsive while solving.)

  • Interrupting your script mid-solve abandons the request: the session finishes the solve, discards it, and cleans up your models. It cannot yet cancel the solver mid-flight.

  • One machine only. The socket is same-user; nothing crosses the network.