ATOM Environment Variables#
This document describes the environment variables used in the ATOM project.
Data parallelism#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_DP_RANK |
int |
0 |
The rank ID for the current process in data parallelism. |
ATOM_DP_RANK_LOCAL |
int |
0 |
The local rank ID for the current process (used in SPMD mode). |
ATOM_DP_SIZE |
int |
1 |
Total number of data parallel ranks. |
ATOM_DP_MASTER_IP |
str |
127.0.0.1 |
Master IP address for DP ranks coordination. |
ATOM_DP_MASTER_PORT |
int |
29500 |
Master port for DP ranks coordination. |
ATOM_DP_LB_REQ_EQUIV |
int |
512 |
Token-equivalent decode pressure assigned to each in-flight request by |
ATOM_DP_SESSION_AFFINITY |
bool |
false |
Load-place each new session, then keep later turns on the same prefix-cache owner. Reads |
Prefill delayer (DP attention)#
Prefill coalescer for DP-attention + EP-MoE serving. Holds back prefill
admission until the accumulated prefill (fresh waiting tokens + resumable
partials’ remaining tokens) fills a worthwhile forward, so fragmented
short-input prefills / small partial tail chunks batch into one forward instead
of firing many tiny ones. Releases when the fill target is reached, when a
must-fire bound trips (no decode to hide behind, KV pressure/starvation, TTFT
deadline, partial deadline), or when the queue stops growing. Preserves
cross-rank phase alignment (releases only when every rank is prefill-ready,
unless a bound forces it). All timing is tick-based (deterministic across ranks —
no wall-clock skew). See atom/model_engine/prefill_delayer.py. Active only when
data_parallel_size > 1.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_ENABLE_PREFILL_DELAYER |
bool |
true |
Master switch for the prefill coalescer. |
ATOM_PREFILL_DELAYER_TARGET_FILL |
float |
0.9 |
Release once accumulated pending tokens reach |
ATOM_PREFILL_DELAYER_TTFT_MAX_TICKS |
int |
200 |
Max consecutive scheduler ticks a held prefill waits before force-release. Values |
ATOM_PREFILL_DELAYER_PARTIAL_MAX_TICKS |
int |
100 |
Tighter bound for a held mid-chunked-prefill (it holds allocated KV). Values |
ATOM_PREFILL_DELAYER_STALL_TICKS |
int |
10 |
After this many consecutive non-growing ticks, release (burst ended, more won’t come). Values |
ATOM_PREFILL_DELAYER_KV_HIGH_WATERMARK |
float |
0.9 |
At/above this KV usage a prefillable rank force-releases (can’t accumulate a bigger batch anyway). |
ATOM_PREFILL_DELAYER_TOKEN_USAGE_LOW_WATERMARK |
float|”” |
“” (None) |
If set, a prefillable rank below this KV usage force-releases (GPU starving). |
ATOM_PREFILL_DELAYER_MAX_QUEUE_MS |
float|”” |
“” (None) |
TTFT SLA guard: if any rank’s oldest schedulable waiting prefill has queued (since arrival) ≥ this many ms, force-release regardless of the fill target. Measures true end-to-end wait (backlog + coalescer holds), unlike the tick-based TTFT bound which only caps one hold episode. Empty = disabled; set to your TTFT budget (a small value under heavy backlog fires every tick and defeats coalescing). |
ATOM_PREFILL_DECODE_INTERVAL |
int |
0 |
After an executed prefill forward, protect this many scheduler passes for decode before admitting another prefill. |
ATOM_PREFILL_DELAYER_DEBUG |
bool |
false |
Per-tick FIRE/HOLD debug logging. |
ATOM_PREFILL_DELAYER_LOG_EVERY |
int |
1000 |
Emit aggregate stats (per-exit fire counts + hold rate) every N decisions (0 disables). |
Model loading#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_DISABLE_MMAP |
bool |
false |
If set to |
ATOM_LOADER_NUM_THREADS |
int |
16 |
Worker threads for weight loading. |
ATOM_LOADER_STRICT_COVERAGE |
bool |
|
Fail loading when a fused MoE parameter does not receive every routed expert from the checkpoint. Set to |
ATOM_LOADER_PREFETCH |
bool |
|
Warm the page cache by reading this rank’s share of the checkpoint sequentially on a background thread, instead of leaving it to demand faults through the mmap. The fault pattern sustains ~3.2 GB/s on a local NVMe that a single sequential reader drives at 6.06 GB/s, so this is an access-pattern fix, not a queue-depth one. Measured on DeepSeek-R1 MXFP4 (350 GiB, TP=4): cold load 154s → 69s. Set to |
ATOM_LOADER_PREFETCH_THREADS |
int |
4 |
Concurrent sequential readers used by the prefetcher. The device saturates at ~2 streams, so raising this mostly adds contention with the loader; |
ATOM_LOADER_PREFETCH_BLOCK_MB |
int |
16 |
Read block size for the prefetcher, in MiB. |
ATOM_LOADER_FADVISE |
bool |
|
Issue |
ATOM_ONLINE_QUANT_STREAMING |
bool |
|
Opt in to quantizing eligible online-quant modules as soon as their checkpoint weights are complete, then release source storage to reduce load-time peak memory. Only active with a valid online quantization config. See the streaming online quantization guide. |
ATOM_ONLINE_QUANT_STREAMING_HOST_STAGING |
bool |
|
Assemble streamed module weights in CPU storage before one H2D transfer. Keeps the checkpoint walk parallel; disabling it buffers loader calls and forces the checkpoint walk to one thread. |
ATOM_ONLINE_QUANT_STREAMING_THREADS |
int |
|
Tail workers for H2D, per-module quantization, and source release. More workers increase overlap and in-flight memory; |
Plugin mode#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_DISABLE_VLLM_PLUGIN |
bool |
0 (false) |
If set to |
Kernel / backend selection#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_USE_TRITON_GEMM |
bool |
0 (false) |
If set to |
ATOM_USE_FP4_NON_SHUFFLE_TRITON_GEMM |
bool |
0 (false) |
If set to |
ATOM_USE_TRITON_MXFP4_BMM |
bool |
0 (false) |
If set to |
MoE all2all (MoRI) wire format#
Both are opt-in and default to off; they only apply with DP attention + expert
parallelism. They are not symmetric — FP4 dispatch only moves a quantization
the MoE GEMM was going to perform anyway (it consumes FP4 activations either
way, and per_1x32 is per-row, so it does not matter which rank runs it), while
FP8 combine adds a quantization that would not otherwise happen, since the
expert output is bf16. Treat the dispatch knob as format matching and the
combine knob as a quality/throughput tradeoff.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_MORI_FP4_DISPATCH |
bool |
0 (false) |
If set to |
ATOM_MORI_COMBINE_QUANT |
str |
|
Combine-side codec passed into the MoRI config. |
Fusion passes#
TP AllReduce fusion#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_ENABLE_ALLREDUCE_RMSNORM_FUSION |
bool |
1 (true) |
If set to |
DeepSeek-style#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_ENABLE_DS_INPUT_RMSNORM_QUANT_FUSION |
bool |
1 (true) |
If set to |
ATOM_ENABLE_DS_QKNORM_FUSION |
bool |
1 (true) |
If set to |
ATOM_ENABLE_DS_QKNORM_QUANT_FUSION |
bool |
1 (true) |
If set to |
ATOM_DUAL_STREAM_MOE_TOKEN_THRESHOLD |
int |
1024 |
Upper bound on MoE token count ( |
ATOM_DUAL_STREAM_PIECEWISE |
bool |
0 |
Opt-in: allow a PIECEWISE-captured graph piece to hold the MoE dual-stream fork/join (shared experts on |
DSpark block sampling#
DSpark drafts a num_speculative_tokens-wide block in one backbone pass, then
samples it left-to-right with a low-rank first-order Markov head
(logits_k = base_logits_k + W1[x_{k-1}] @ W2ᵀ, x_k = argmax(logits_k)). The
unfused loop casts the whole [V, r] W2 table to fp32 on every iteration and
materializes two [B, V] fp32 tensors that only an argmax reads. See
atom/model_ops/dspark_markov_sample.py.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_DSPARK_FUSED_MARKOV_SAMPLE |
bool |
1 (true) |
Sample the DSpark block with a fused Triton kernel that computes the rank- |
Qwen3 style#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_ENABLE_QK_NORM_ROPE_CACHE_QUANT_FUSION |
bool |
0 (false) |
If set to |
Llama-style#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_LLAMA_ENABLE_AITER_TRITON_FUSED_RMSNORM_QUANT |
bool |
1 (true) |
If set to |
ATOM_LLAMA_ENABLE_AITER_TRITON_FUSED_SILU_MUL_QUANT |
bool |
1 (true) |
If set to |
Draft CUDAGraphs (all drafter flavors)#
A drafter declares its forward passes as DraftGraphs (atom/spec_decode/drafter.py).
At the end of CUDAGraph capture the runner runs each one once per captured batch
size, so the per-shape JIT — aiter’s flydsl builds an hgemm per tile config,
in-process — is paid at startup instead of stalling a serving step. At serve
time a pass runs at the batch the target just ran, which ForwardMode.decide
picks out of those same capture_sizes — that is what makes a warmed shape and a
reachable shape one set rather than two lists that drift. The switch below decides whether that warm also records.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_DRAFT_CUDAGRAPH |
bool |
1 (true) |
Capture each declared draft pass into a per- |
DSpark drafting#
The Kimi-K3 DSpark draft writes the target’s context rows into its own paged MLA cache once per draft layer per drafting step; the switch below shortens that path. The first write of each process logs which path it took, and logs again if that ever changes, so a fusion left inert by an unrecognised layout says so.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_DSPARK_FUSED_CTX_KV |
bool |
1 (true) |
Write the context rows with one Triton kernel (RMSNorm + RoPE + concat + paged store) instead of four launches plus a throwaway |
V4 attention backend (Migration)#
Selects between the legacy per-seq Python dispatch path in atom/models/deepseek_v4.py
and the new batched V4AttentionBackend (atom/model_ops/v4_attention_backend.py).
The new backend removes ~256 GPU→CPU .item() syncs per forward and is required
to enable CUDAGraph capture for V4. Legacy stays available during PR-A migration
for byte-equal A/B verification via dump-bisect; it is removed once all phases
land. See atom/model_ops/v4_backend_gate.py for the selector.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_V4_BACKEND |
str |
|
|
ATOM_V4_BACKEND_LAYERS |
csv int |
“” (= all) |
Comma-separated layer ids that use the new backend (others stay legacy). Empty means: apply |
State checkpoints#
For models carrying per-request recurrent state (GDN: Qwen3-Next / Qwen3.5;
Kimi-K3’s KDA; DeepSeek-V4’s compressor ring), a checkpoint lets a later prefix
hit resume mid-prompt instead of recomputing from zero. Where they are placed
is a policy, set by --state-checkpoint-interval-tokens (three regimes carried
by the sign — see the configuration guide) and the
flag below. Details in the state-checkpoint section of the
scheduling & KV cache guide.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_STATE_CHECKPOINT_DEMAND |
bool |
1 (true) |
Set to |
Profiling & debugging#
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_TORCH_PROFILER_DIR |
str |
— |
When set, enables PyTorch profiler and writes traces to this directory. Create subdirectories per rank (e.g., |
ATOM_PROFILER_MORE |
bool |
0 (false) |
When |
ATOM_ENABLE_DETAILED_ANNOTATION |
bool |
0 (false) |
When profiling is active, appends detailed attention aggregates to the |
ATOM_LOG_MORE |
bool |
0 (false) |
If set to |
Garbage collection#
CPython’s generation-2 pass is stop-the-world and walks every tracked
container, so its cost tracks the live heap — which in a serving process is
almost entirely startup state (model, compiled graph, tokenizer, KV block
pool) that is never garbage. Measured on DeepSeek-V4-Flash-DSpark tp1: 242.8 ms
in the EngineCore, up to 596 ms in a ModelRunner worker, while reclaiming zero
objects once startup was done. See atom/utils/gc_utils.py.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_GC_FREEZE |
bool |
1 (true) |
Move the startup heap into CPython’s permanent generation once warmup is done, so collections stop scanning it. Applied in every process that outlives startup — the API server, the atomesh frontend, every EngineCore and every ModelRunner worker; undone on engine shutdown so an in-process teardown does not leak. Set |
ATOM_GC_DEBUG |
bool |
0 (false) |
Log every collection: generation, duration, objects reclaimed, objects tracked. Costly — counting the tracked set on every pass added ~90s of startup on a V4-Flash tp1 — but the only way to see these pauses, since a stall in the EngineCore idles the workers with no event in their torch trace. |
ATOM_GC_THRESHOLD |
csv int |
“” (= CPython default 700,10,10) |
|
Debug dump (atom.utils.debug_helper)#
Env-gated dump / compare / monkey-patch primitives for forward bisect &
batch invariance investigation. All entries are no-op when their
controlling *_DIR is unset, so they are safe to leave wired into
production paths. See .claude/skills/dump-bisect-debug.md for the
methodology and atom/utils/debug_helper/ for the implementation.
Variable |
Type |
Default |
Description |
|---|---|---|---|
ATOM_FWD_DUMP_DIR |
str |
— |
Enables |
ATOM_FWD_DUMP_LAYERS |
csv int |
“” (= all) |
Comma-separated layer ids to dump (e.g. |
ATOM_FWD_DUMP_BLOCK_CLASS |
csv str |
|
Module class names to hook. Multiple values supported (e.g. |
ATOM_FWD_DUMP_LAYER_ATTR |
str |
|
Attribute name on the block carrying its index. Some non-DeepSeek models use |
ATOM_FWD_DUMP_ONE_SHOT |
bool |
1 (true) |
When |
ATOM_WEIGHT_DUMP_DIR |
str |
— |
Enables |
ATOM_WEIGHT_DUMP_LAYERS |
csv int |
|
Comma-separated layer ids to dump weights for. |
ATOM_WEIGHT_DUMP_EXIT |
bool |
1 (true) |
When |
ATOM_DEBUG_TOPK |
int |
0 |
Set to |
ATOM_DEBUG_TOPK_PATH |
str |
— |
Optional output file for top-K logs. Writes to stderr if unset. |
CLI for comparing dumps:
python -m atom.utils.debug_helper.compare slot-invariance --dir DIR --n-slots 4
python -m atom.utils.debug_helper.compare ref-vs-target --dir DIR
python -m atom.utils.debug_helper.compare layer-bisect --dir DIR --threshold 0.99
python -m atom.utils.debug_helper.compare schema --a A.pt --b B.pt
Benchmarks (optional)#
Variable |
Type |
Default |
Description |
|---|---|---|---|
OPENAI_API_KEY |
str |
— |
API key for OpenAI-compatible benchmark requests. |
VLLM_USE_MODELSCOPE |
bool |
false |
If set to |
SAVE_TO_PYTORCH_BENCHMARK_FORMAT |
bool |
false |
If set, save benchmark results in PyTorch benchmark format. |
Internal / Set by ATOM#
The following variables are set internally by ATOM; users typically do not need to configure them:
Variable |
Description |
|---|---|
AITER_QUICK_REDUCE_QUANTIZATION |
Set to |
TORCHINDUCTOR_CACHE_DIR |
Set by compiler interface for inductor cache. |
TRITON_CACHE_DIR |
Set by compiler interface for Triton cache. |
Reference#
Environment variables are defined and accessed via atom.utils.envs:
from atom.utils import envs
# Example: check data parallel size
dp_size = envs.ATOM_DP_SIZE
See atom/utils/envs.py for the full list of lazy-evaluated environment variables.