Files
TheRock/rocm-systems/emulation/mirage/docs/host.md
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

129 lines
5.9 KiB
Markdown

# The mirage host process
The host is the per-session worker that brings a session to life. There is
exactly one host per session (the orchestrator host on the real machine);
when it exits, the session is considered stopped. It is the same `mirage`
binary, invoked as `mirage host --session <id>`, and is normally spawned for
you by `mirage session start` and `mirage run`.
## Lifecycle
```text
┌──────────────────┐
CLI calls │ session create() │
session start │ writes def.json │
─────────▶ │
└────────┬─────────┘
│ spawn detached, new process group
▼
┌───────────────────────┐ ┌──────────────────────────┐
│ mirage host │───▶│ writes node/<rank>/pid │
│ --session <id> │ │ writes health.json │
│ │ │ { healthy: true, │
│ poll exec/ directory │ │ state: "ready" } │
└───────────┬───────────┘ └──────────────────────────┘
│ new exec/<id>/def.json appears
▼
┌───────────────────────┐
│ for each node n: │
│ mkfifo stdin │
│ open stdout │
│ spawn child (PTY) │
│ write node/<n>/pid │
└───────────┬───────────┘
▼
┌───────────────────────┐
│ wait(child) │
│ write exit_code │
│ update status.json │
│ if !keep, rm exec dir │
└───────────────────────┘
```
On `SIGTERM`/`SIGINT` the host:
1. Sets health `state="stopping", healthy=false`.
2. Signals every per-node child recorded under `exec/*/node/*/pid`.
3. Waits briefly, then escalates to `SIGKILL` for anything still alive.
4. Sets health `state="stopped"` and exits cleanly.
## Health states
`health.json` carries a `state` that is one of `starting`, `pulling`
(container image), `ready`, `degraded`, `stopping`, `stopped`, or `error`,
together with `healthy` and `terminal` booleans and an optional `message`.
`mirage session wait` and the `run`/`session start` ready-wait poll
`health.json` until `healthy=true` or the session becomes terminal — a
terminal-but-unhealthy session (a bad image, a node that won't start, a
missing emulator asset) is treated as a hard failure so the CLI never submits
an exec that no host will ever run.
## Polling cadence
The host polls `exec/` on a fixed, sub-second tick to discover new exec
definitions. Polling (rather than `inotify`) was chosen for portability and
simplicity; it is fast enough to feel interactive and cheap enough to be
invisible on idle systems.
## What the host watches
* `exec/<id>/def.json` — its appearance triggers a new exec launch.
* `exec/<id>/status.json` — the host (re)writes this; `ended=true` marks the
exec done.
It does not watch profiles: a profile is resolved by the CLI on session
create and inlined into the session's `def.json` as needed.
## Containerised sessions
When a profile (or `--image`/`--mount`/`--container-provider` override) requests
containerisation, the orchestrator host brings up one container per node
through the configured provider (podman or docker, autodetected), bind-mounts
the session directory in, and launches a per-node `mirage host` *inside* each
container. Those inner hosts run only their own node's execs and never manage
containers themselves. The provider, image, and per-node container ids are
recorded in the session state and surfaced by `mirage session list`.
The container provider can be selected with `--container-provider` or the
`MIRAGE_CONTAINER_PROVIDER` environment variable.
## Recovery
The session host is re-execable. Restarting `mirage host --session <id>` is
safe:
* The node's `pid` file is overwritten.
* Already-finished execs (`status.json: ended=true`) are skipped.
* In-progress execs whose child is still alive are not re-adopted (their stdio
FDs were owned by the previous host); they remain visible as
`started=true, ended=false` with a stale pid.
## Extending the host
The host is a thin orchestrator. Per-emulator behaviour lives behind the
`mirage_core::emulator::Emulator` trait:
* `injection_def()` returns env vars, files, and `LD_PRELOAD` entries added to
every child.
* `validate_profile()` checks a profile is runnable (reported at
`profile create` time).
* `health()` returns a snapshot the host periodically publishes.
To add a backend, implement `Emulator`, register it via `inventory`, and add
its Cargo feature (see [`architecture.md`](architecture.md)). No `match` arm in
the host needs editing.
## Environment
| Variable | Effect |
| ----------------- | ----------------------------------------------------- |
| `MIRAGE_LOG` | Tracing filter, e.g. `debug` or `mirage_host=debug`. |
| `MIRAGE_RUNTIME` | Override the runtime dir holding the session directory (else `$XDG_RUNTIME_DIR/mirage`). |
A `-v`/`-vv` passed to the CLI is propagated to the detached host via
`MIRAGE_LOG`, so host events land in `node/<rank>/host.log` at the requested
verbosity. Children inherit only a curated set of variables (`PATH`, `HOME`,
`USER`, `LANG`, `LC_ALL`, `TERM`, `TMPDIR`); to add more, set them in the
exec's `--env` or via the emulator's `injection_def()`.