# `EMLX.Application`
[🔗](https://github.com/elixir-nx/emlx/blob/v0.3.0/emlx/lib/emlx/application.ex#L1)

OTP Application for EMLX.

Allocates the application-default `EMLX.CommandQueue` (one per device:
`:cpu` and `:gpu`) at boot and stashes the NIF resource references in
`:persistent_term`. These are the workers used by `EMLX.eval/1` and
`EMLX.to_blob/1` for any process that has not bound its own queue via
`EMLX.CommandQueue.with_queue/2`.

See `clean-room-import/01-worker-thread-dispatch.md` for the rationale
behind `:persistent_term` instead of a `GenServer` + `Registry`.

## Idempotency

`start/2` is safe to call more than once (e.g. from an umbrella where
`:emlx` is referenced by several apps). The first call to allocate a
worker for a given device wins; subsequent calls observe the existing
`:persistent_term` entry and skip. This matters because every
`:persistent_term.put/2` triggers a global GC scan across every
process heap on the node — we do exactly two puts (CPU + GPU) over
the BEAM's lifetime.

## GPU absence

On platforms where MLX cannot allocate a GPU stream (e.g. Linux without
Metal), `EMLX.NIF.command_queue_new(:gpu)` returns `{:error, _}` and
this module silently skips the GPU worker. Subsequent
`EMLX.eval/1` calls on a GPU tensor will raise at use time with the
underlying `:persistent_term` `ArgumentError`.

# `default_worker`

```elixir
@spec default_worker(:cpu | :gpu) :: reference()
```

Returns the application-default `EMLX.CommandQueue` NIF resource for
the given device.

Raises `ArgumentError` if no worker has been allocated for the device
(e.g. asking for `:gpu` on a system without Metal).

**Never** call `:persistent_term.put/2` on the underlying key
(`{EMLX, :default_worker, device}`) — overwriting a `:persistent_term`
value triggers a node-wide GC.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
