rtx-csm: Phase 8.2 — extended boot warm-up (~50% TTFA reduction)
Increased the boot warm-up from `max_audio_ms=200` (~3 frames) to `max_audio_ms=2000` (~25 frames) and switched the prompt to a fuller sentence so more Metal kernel paths fire during the throwaway gen. The original 200 ms warm-up only compiled the early fast paths; the first user turn still paid 4-5 s of additional kernel compilation as new branches lit up under longer-context generation. The 2 s warm-up gives the JIT a chance to compile everything. 3-turn bench (mock LLM, Q8 + stream, M-series Metal, 10.43 s LibriSpeech in): Metric Original warm-up Extended warm-up Δ Boot warm-up cost 819 ms 2748 ms +1.9 s client first_audio_ms p50 4915 ms 529 ms -89% llm_to_first_audio 4892 ms 627 ms -87% total_turn 18408 ms 18112 ms wash Sub-second TTFA on every turn. The extra 2 s at boot is paid back on the first user turn — every turn after is pure win. This is the new production-recommended config: --quantized-gguf <Q8> --stream-tts --vad-gate (warm-up always on; no flag toggle). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
@@ -548,19 +548,26 @@ async fn main() -> Result<()> {
|
|||||||
};
|
};
|
||||||
tracing::info!("models loaded");
|
tracing::info!("models loaded");
|
||||||
|
|
||||||
// Warm up the Generator: do one throwaway generate() so Metal kernel
|
// Warm up the Generator: a longer throwaway generate() so the full
|
||||||
// compilation + first-frame KV cache init happen now, not on the
|
// Metal kernel set (backbone + depth decoder + Mimi decode + every
|
||||||
// first user turn. Empirically this eliminates ~5-6s of dead time
|
// sampler path) compiles up-front. Empirically eliminates ~4-6 s
|
||||||
// from the first-sentence TTS gen latency. Cost is paid once at
|
// from the first-sentence TTS gen latency. Cost is paid once at
|
||||||
// boot. The throwaway audio is discarded.
|
// boot. Phase 8.2 raised this from 200 ms to 2000 ms (~25 frames)
|
||||||
|
// because at 200 ms only the early code paths fired — variable
|
||||||
|
// first-sentence cost still showed up on first user turn.
|
||||||
let warmup_t = std::time::Instant::now();
|
let warmup_t = std::time::Instant::now();
|
||||||
{
|
{
|
||||||
let opts = GenerateOptions {
|
let opts = GenerateOptions {
|
||||||
max_audio_ms: 200,
|
max_audio_ms: 2000,
|
||||||
seed: 0,
|
seed: 0,
|
||||||
..GenerateOptions::default()
|
..GenerateOptions::default()
|
||||||
};
|
};
|
||||||
match generator.generate("Hi.", cli.speaker, &[], opts) {
|
match generator.generate(
|
||||||
|
"Warming up the speech model with a slightly longer prompt.",
|
||||||
|
cli.speaker,
|
||||||
|
&[],
|
||||||
|
opts,
|
||||||
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"generator warm-up complete ({}ms)",
|
"generator warm-up complete ({}ms)",
|
||||||
|
|||||||
Reference in New Issue
Block a user