Integrate DS4 execution parity in Rust
This commit is contained in:
@@ -3,6 +3,7 @@ use super::*;
|
||||
#[derive(Clone)]
|
||||
pub(super) struct PreferenceDraft {
|
||||
pub(super) model: ModelChoice,
|
||||
pub(super) legacy_mtp_enabled: bool,
|
||||
pub(super) dspark_enabled: bool,
|
||||
pub(super) idle_timeout_minutes: String,
|
||||
pub(super) endpoint_port: String,
|
||||
@@ -51,6 +52,7 @@ impl PreferenceDraft {
|
||||
let speculative = &runtime.speculative;
|
||||
Self {
|
||||
model: config.model,
|
||||
legacy_mtp_enabled: speculative.legacy_mtp_enabled,
|
||||
dspark_enabled: speculative.dspark_enabled,
|
||||
idle_timeout_minutes: config.idle_timeout_minutes.to_string(),
|
||||
endpoint_port: config.endpoint.port.to_string(),
|
||||
@@ -136,6 +138,7 @@ impl PreferenceDraft {
|
||||
Ok(SpeculativePreferences {
|
||||
mtp_draft_tokens: parse_positive_i32("MTP draft tokens", &self.mtp_draft_tokens)?,
|
||||
mtp_margin: parse_f32("MTP margin", &self.mtp_margin)?,
|
||||
legacy_mtp_enabled: self.legacy_mtp_enabled,
|
||||
glm_mtp: self.glm_mtp,
|
||||
glm_mtp_timing: self.glm_mtp_timing,
|
||||
dspark_enabled: self.dspark_enabled,
|
||||
|
||||
@@ -3,6 +3,19 @@ use iced::widget::column;
|
||||
|
||||
impl App {
|
||||
pub(super) fn preferences_panel(&self) -> Element<'_, Message> {
|
||||
let legacy_mtp_toggle: Option<fn(bool) -> Message> = self
|
||||
.preference_draft
|
||||
.model
|
||||
.supports_dspark()
|
||||
.then_some(Message::PreferenceLegacyMtpChanged);
|
||||
let legacy_mtp = hint(
|
||||
checkbox(
|
||||
"Enable legacy MTP for this model",
|
||||
self.preference_draft.legacy_mtp_enabled,
|
||||
)
|
||||
.on_toggle_maybe(legacy_mtp_toggle),
|
||||
"Uses the managed one-stage MTP support GGUF. The target model verifies every drafted token; it is mutually exclusive with DSpark.",
|
||||
);
|
||||
let dspark_toggle: Option<fn(bool) -> Message> = self
|
||||
.preference_draft
|
||||
.model
|
||||
@@ -14,7 +27,7 @@ impl App {
|
||||
self.preference_draft.dspark_enabled,
|
||||
)
|
||||
.on_toggle_maybe(dspark_toggle),
|
||||
"Speculative decoding with the managed DSpark draft artifact: a small model proposes tokens that the main model verifies in one pass. Usually a large speedup, and it cannot be combined with SSD streaming.",
|
||||
"Speculative decoding with the managed DSpark draft artifact: a small model proposes tokens that the main model verifies in one pass. Usually a large speedup; the target model may also stream routed experts from SSD.",
|
||||
);
|
||||
let glm_mtp_toggle: Option<fn(bool) -> Message> = (self.preference_draft.model
|
||||
== ModelChoice::Glm52)
|
||||
@@ -311,6 +324,7 @@ impl App {
|
||||
.on_toggle_maybe(glm_mtp_timing_toggle),
|
||||
"Records per-stage timings of the speculative path to the log, to show where the acceleration actually goes. A diagnostic aid that costs a little throughput.",
|
||||
),
|
||||
legacy_mtp,
|
||||
dspark,
|
||||
preference_input_row(
|
||||
"DSpark confidence threshold",
|
||||
@@ -326,7 +340,7 @@ impl App {
|
||||
"Lets the draft model only propose, never decide: every token is sampled by the full model. Gives up some of the speedup in exchange for output identical to non-speculative decoding.",
|
||||
),
|
||||
text(if self.preference_draft.model.supports_dspark() {
|
||||
"DSpark uses the managed support artifact; entering a threshold or enabling strict mode also enables DSpark."
|
||||
"Legacy MTP and DSpark use separate managed support artifacts; entering a DSpark threshold or enabling strict mode selects DSpark."
|
||||
} else if self.preference_draft.model == ModelChoice::Glm52 {
|
||||
"GLM MTP is integrated; DSpark is unavailable for this model."
|
||||
} else {
|
||||
@@ -339,9 +353,10 @@ impl App {
|
||||
|engine| {
|
||||
let settings = engine.speculative;
|
||||
format!(
|
||||
"Engine: MTP draft {} • margin {} • GLM MTP {} • timing {} • DSpark {} • confidence {}{} • target-only {}",
|
||||
"Engine: MTP draft {} • margin {} • legacy MTP {} • GLM MTP {} • timing {} • DSpark {} • confidence {}{} • target-only {}",
|
||||
settings.mtp_draft_tokens,
|
||||
settings.mtp_margin,
|
||||
if self.preference_draft.legacy_mtp_enabled { "on" } else { "off" },
|
||||
if settings.glm_mtp { "on" } else { "off" },
|
||||
if settings.glm_mtp_timing { "on" } else { "off" },
|
||||
if settings.dspark { "on" } else { "off" },
|
||||
@@ -357,7 +372,7 @@ impl App {
|
||||
hint(
|
||||
checkbox("Enable SSD-backed model streaming", self.preference_draft.ssd_streaming)
|
||||
.on_toggle(Message::PreferenceSsdChanged),
|
||||
"Leaves the routed expert weights on disk and pages them in as they are needed, so a model larger than this machine's memory still runs. Every cache miss waits for the SSD, and DSpark cannot run alongside it.",
|
||||
"Leaves the routed expert weights on disk and pages them in as they are needed, so a model larger than this machine's memory still runs. Every cache miss waits for the SSD; speculative support weights remain resident while target experts stream.",
|
||||
),
|
||||
hint(
|
||||
checkbox("Skip automatic expert preload", self.preference_draft.ssd_streaming_cold)
|
||||
@@ -381,7 +396,7 @@ impl App {
|
||||
text_input("Automatic", &self.preference_draft.ssd_preload_experts)
|
||||
.on_input(Message::PreferenceSsdPreloadChanged),
|
||||
),
|
||||
text("A blank full-layer value is automatic; an explicit 0 disables fully resident GLM layers. SSD streaming and DSpark are mutually exclusive.")
|
||||
text("A blank full-layer value is automatic; an explicit 0 disables fully resident GLM layers. Flash legacy MTP and DSpark support weights remain resident when target experts stream.")
|
||||
.size(12),
|
||||
text(engine.as_ref().map_or_else(
|
||||
|| "Effective SSD settings will appear after valid values are entered."
|
||||
|
||||
@@ -198,6 +198,55 @@ impl App {
|
||||
.spacing(7)
|
||||
.into(),
|
||||
);
|
||||
let ssd_activity = stats_panel(
|
||||
"SSD STREAMING ACTIVITY · LAST 24 SECONDS",
|
||||
column![
|
||||
mini_chart(
|
||||
&self.metrics_history,
|
||||
|point| point.ssd_requests_per_second,
|
||||
Color::from_rgb8(240, 180, 70),
|
||||
),
|
||||
row![
|
||||
text("Selected loads")
|
||||
.size(12)
|
||||
.color(Color::from_rgb8(240, 180, 70)),
|
||||
Space::with_width(Length::Fill),
|
||||
text(format!("{:.1}/s", latest.ssd_requests_per_second))
|
||||
.size(12)
|
||||
.color(muted_text()),
|
||||
],
|
||||
mini_chart(
|
||||
&self.metrics_history,
|
||||
|point| point.ssd_bytes_per_second,
|
||||
Color::from_rgb8(67, 194, 203),
|
||||
),
|
||||
row![
|
||||
text("Requested expert data")
|
||||
.size(12)
|
||||
.color(Color::from_rgb8(67, 194, 203)),
|
||||
Space::with_width(Length::Fill),
|
||||
text(format_rate(latest.ssd_bytes_per_second))
|
||||
.size(12)
|
||||
.color(muted_text()),
|
||||
],
|
||||
mini_chart(
|
||||
&self.metrics_history,
|
||||
|point| point.ssd_wait_ms_per_second,
|
||||
Color::from_rgb8(220, 80, 86),
|
||||
),
|
||||
row![
|
||||
text("Inference wait")
|
||||
.size(12)
|
||||
.color(Color::from_rgb8(220, 80, 86)),
|
||||
Space::with_width(Length::Fill),
|
||||
text(format!("{:.0} ms/s", latest.ssd_wait_ms_per_second))
|
||||
.size(12)
|
||||
.color(muted_text()),
|
||||
],
|
||||
]
|
||||
.spacing(7)
|
||||
.into(),
|
||||
);
|
||||
|
||||
let model = stats_panel(
|
||||
"MODEL CORE",
|
||||
@@ -249,6 +298,86 @@ impl App {
|
||||
.spacing(9)
|
||||
.into(),
|
||||
);
|
||||
let acceptance = if stats.drafted_tokens == 0 {
|
||||
0.0
|
||||
} else {
|
||||
stats.accepted_draft_tokens as f64 / stats.drafted_tokens as f64
|
||||
};
|
||||
let target_passes = stats
|
||||
.speculative_cycles
|
||||
.saturating_add(stats.verifier_passes);
|
||||
let effective_speedup = if target_passes == 0 {
|
||||
1.0
|
||||
} else {
|
||||
stats
|
||||
.speculative_cycles
|
||||
.saturating_add(stats.accepted_draft_tokens) as f64
|
||||
/ target_passes as f64
|
||||
};
|
||||
let speculative = stats_panel(
|
||||
"SPECULATIVE DECODING",
|
||||
column![
|
||||
metric_row(
|
||||
"Mode",
|
||||
match stats.speculative_mode {
|
||||
1 => "Legacy MTP",
|
||||
2 => "DSpark",
|
||||
_ => "Off",
|
||||
},
|
||||
),
|
||||
metric_row("Cycles", format_count(stats.speculative_cycles)),
|
||||
metric_row("Drafted", format_count(stats.drafted_tokens)),
|
||||
metric_row("Accepted", format_count(stats.accepted_draft_tokens)),
|
||||
metric_row("Acceptance", format!("{:.1}%", acceptance * 100.0)),
|
||||
metric_row(
|
||||
"Target verifier passes",
|
||||
format_count(stats.verifier_passes)
|
||||
),
|
||||
metric_row("Verifier wall time", format_milliseconds(stats.verifier_ms)),
|
||||
metric_row(
|
||||
"Effective target-pass speedup",
|
||||
format!("{effective_speedup:.2}×")
|
||||
),
|
||||
]
|
||||
.spacing(9)
|
||||
.into(),
|
||||
);
|
||||
let ssd = stats_panel(
|
||||
"SSD EXPERT STREAMING",
|
||||
column![
|
||||
metric_row("State", if stats.ssd_enabled { "Enabled" } else { "Off" }),
|
||||
metric_row("Resident weights", format_bytes(stats.ssd_resident_bytes)),
|
||||
metric_row("Expert cache", format_bytes(stats.ssd_cache_bytes)),
|
||||
metric_row(
|
||||
"Cache capacity",
|
||||
format!("{} experts", stats.ssd_cache_experts)
|
||||
),
|
||||
metric_row(
|
||||
"Preloaded",
|
||||
format!("{} experts", stats.ssd_preloaded_experts)
|
||||
),
|
||||
metric_row(
|
||||
"Selected-load requests",
|
||||
format_count(stats.ssd_selected_requests)
|
||||
),
|
||||
metric_row(
|
||||
"Requested expert bytes",
|
||||
format_bytes(stats.ssd_requested_bytes)
|
||||
),
|
||||
metric_row("Selected-load wait", format_milliseconds(stats.ssd_wait_ms)),
|
||||
metric_row(
|
||||
"Average load wait",
|
||||
format_milliseconds(
|
||||
stats
|
||||
.ssd_wait_ms
|
||||
.checked_div(stats.ssd_selected_requests)
|
||||
.unwrap_or(0)
|
||||
)
|
||||
),
|
||||
]
|
||||
.spacing(9)
|
||||
.into(),
|
||||
);
|
||||
let cache = stats_panel(
|
||||
"KV CACHE",
|
||||
column![
|
||||
@@ -352,10 +481,12 @@ impl App {
|
||||
heading,
|
||||
headline,
|
||||
throughput,
|
||||
ssd_activity,
|
||||
kv_io,
|
||||
requests,
|
||||
disc,
|
||||
row![model, runtime].spacing(10),
|
||||
row![speculative, ssd].spacing(10),
|
||||
row![cache, server].spacing(10),
|
||||
text("Counters are published by the runtime with relaxed atomics and sampled by the UI every 200 ms.")
|
||||
.size(11)
|
||||
|
||||
Reference in New Issue
Block a user