atlas_kernels/ptx_set.rs
1// SPDX-License-Identifier: AGPL-3.0-only
2
3//! The compiled-target declarations `build.rs` emits: what one kernel target
4//! IS, and what it says about itself. Split out of `lib.rs` at the 500-LoC cap.
5//! Exact piecewise move — no logic changed, and the types keep their `crate`
6//! paths (`atlas_kernels::TargetPtxSet`, …) through the `pub use` in `lib.rs`,
7//! which is also what puts them in scope for the `include!`d `target_ptx.rs`
8//! that constructs them.
9//!
10//! Distinct from [`super::query`] and [`super::resolve`], which SELECT among
11//! these declarations; nothing here has behaviour to select with.
12
13use atlas_core::target::KernelTarget;
14
15use super::{ModelBehavior, SamplingPresets};
16
17/// Declares which `(model_type, hidden_size)` pairs a kernel target supports.
18/// Parsed from `[[model_types]]` in MODEL.toml at build time.
19pub struct ModelTypeMatch {
20 pub model_type: &'static str,
21 /// `None` = wildcard (matches any hidden_size not caught by a more specific entry).
22 pub hidden_size: Option<usize>,
23}
24
25/// DFlash speculative-decoding pairing for a target model.
26/// Parsed from `[dflash]` in MODEL.toml at build time. `None` when the
27/// model has no DFlash drafter associated.
28#[derive(Debug, Clone)]
29pub struct DflashConfig {
30 /// HuggingFace id (or local path) of the drafter checkpoint.
31 pub draft_model: &'static str,
32 /// Block size γ (parallel draft tokens per step). Defaults to 16.
33 pub gamma: usize,
34 /// Drafter sliding-window size in tokens. 0 = full attention.
35 pub window_size: usize,
36 /// Token id used to fill the γ "to-be-predicted" positions during
37 /// drafter forward. From the drafter's `dflash_config.mask_token_id`.
38 pub mask_token_id: u32,
39 /// Target-side layer indices to capture intermediate hidden states from
40 /// (shallow-to-deep). The drafter's `fc` projection consumes the stack
41 /// of these hiddens. From the drafter's `dflash_config.target_layer_ids`.
42 pub target_layer_ids: &'static [usize],
43}
44
45/// Kernel modules hyperoptimized for a specific (H, M_q) target.
46///
47/// Each blob is the compiled kernel for one module, emitted uniformly as
48/// `&'static [u8]` by build.rs (`include_bytes!`). NVIDIA PTX is ASCII
49/// text but valid as bytes; SCALE/AMD and Metal produce binary objects.
50/// The runtime registry sniffs text-vs-binary per blob at load time.
51pub struct TargetPtxSet {
52 pub target: KernelTarget,
53 /// The `kernels/<hw>/HARDWARE.toml` `[hardware].arch` this target was
54 /// compiled with, VERBATIM — `sm_90a`, `sm_100a`, `sm_121f`, `gfx1151`.
55 ///
56 /// Additive to [`KernelTarget::arch`], which records the same declaration
57 /// with its feature suffix stripped (`sm_90`, `sm_121`) because that is
58 /// the base SM the target constants, the gate baselines and every existing
59 /// record are keyed by. Both are needed, and they are not interchangeable:
60 ///
61 /// * the base SM is an IDENTITY — "which architecture family is this";
62 /// * this field is the only one a COMPATIBILITY question may be asked of,
63 /// because the suffix IS the rule (`a` never runs forward onto a later
64 /// architecture, `f` stays inside one major family, a bare `sm_XY`
65 /// JIT-compiles forward). Judging the stripped string applies plain
66 /// forward-compat to PTX that has none, which is how `sm_90a` kernels
67 /// passed the GPU preflight on a CC 10.0 device and then failed inside
68 /// `cuModuleLoadData` — the error the preflight exists to replace.
69 ///
70 /// Empty only if a build recorded no architecture. Consumers treat empty
71 /// as "no opinion" and skip, rather than inventing a verdict.
72 pub ptx_arch: &'static str,
73 pub modules: Vec<(&'static str, &'static [u8])>,
74 pub sampling: SamplingPresets,
75 pub behavior: ModelBehavior,
76 pub model_type_matches: Vec<ModelTypeMatch>,
77 /// `[model] match_names` needles from MODEL.toml — case-insensitive
78 /// substrings of the checkpoint reference (HF id / `--model-name` /
79 /// resolved model dir) that identify checkpoints THIS target serves.
80 /// Consulted only to break a tie when several targets declare the same
81 /// `(model_type, hidden_size)` (e.g. qwen3.6-27b vs qwen3.8-27b, whose
82 /// configs are bit-identical); see [`crate::resolve::resolve_target`]. Empty
83 /// for targets that never collide — `build.rs` panics if a colliding
84 /// target omits them.
85 pub match_names: &'static [&'static str],
86 /// DFlash drafter pairing for this model. `None` when the MODEL.toml has
87 /// no `[dflash]` section. Consumed by spark-server when `--dflash` is
88 /// set without an explicit `--draft-model` flag.
89 pub dflash: Option<DflashConfig>,
90 /// `(module, kernel)` pairs this model's kernel files DROPPED by shadowing
91 /// their `common/` namesakes — the kernel exists in `common/` but this
92 /// model's fork of the file does not define it, so it is not compiled here.
93 ///
94 /// Shadowing is whole-file, so a fork that predates a kernel added to
95 /// `common/` silently loses it: `try_kernel` returns handle 0 and whatever
96 /// depends on it fails CLOSED. The startup audit joins this against the
97 /// kernels the model actually looked up, which separates the two classes of
98 /// missing kernel — dropped-by-fork (a build defect) from
99 /// never-built-for-this-architecture (expected, e.g. MLA on a Qwen model).
100 pub shadowed_dropped: &'static [(&'static str, &'static str)],
101 /// `(module, kernel)` lookups this model's dispatch may issue and fail to
102 /// resolve WITHOUT that being an error, declared in the model's MODEL.toml
103 /// `[expected_absent]` with a mandatory stated reason per entry.
104 ///
105 /// The boot audit (`kernel_audit::classify_failures`) fails CLOSED on every
106 /// unresolved lookup that is not in this list, so the list is the entire
107 /// difference between "this model is known to run this way" and "nobody has
108 /// looked". It is TRANSITIONAL: the right fix for a lookup that can never
109 /// resolve is to gate it on config so it is never issued (see
110 /// `qwen3_attention::init_arch_gates`), which removes it from here.
111 pub expected_absent: &'static [(&'static str, &'static str)],
112}