1use crate::llm_lifecycle::{default_vault_path, init_log_stream};
6use qualia_client_core::model_lifecycle::{resolve_vault_model, scan_vault_gguf, VaultGgufEntry};
7use std::path::{Path, PathBuf};
8
9pub fn run_test_models(
11 vault_path: Option<PathBuf>,
12 models: Option<Vec<String>>,
13 _quantization: Option<String>,
14 verbose: bool,
15) -> Result<(), String> {
16 let vault_path = vault_path.unwrap_or_else(default_vault_path);
17
18 if verbose {
19 init_log_stream(true);
20 }
21
22 println!("๐ Starting LLM Model Testing CLI");
23 println!("๐ Vault path: {}", vault_path.display());
24
25 let available_models =
27 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
28
29 if available_models.is_empty() {
30 return Err("No GGUF models found in vault".to_string());
31 }
32
33 println!("๐ฆ Found {} model(s):", available_models.len());
34 for model in &available_models {
35 println!(" - {}", model.name);
36 }
37
38 let test_models = if let Some(ref requested) = models {
40 available_models
41 .iter()
42 .filter(|m| requested.contains(&m.name))
43 .cloned()
44 .collect()
45 } else {
46 available_models
47 };
48
49 if test_models.is_empty() {
50 return Err("No matching models found".to_string());
51 }
52
53 println!("\n๐งช Testing {} model(s)...", test_models.len());
54
55 for model in &test_models {
56 println!("\n๐ Testing: {}", model.name);
57 match test_single_model(&vault_path, model, verbose) {
58 Ok(result) => {
59 println!(" โ
Load time: {}ms", result.load_time_ms);
60 println!(" โ
Memory: {}MB", result.memory_mb);
61 println!(
62 " โ
Status: {}",
63 if result.success { "PASS" } else { "FAIL" }
64 );
65 }
66 Err(e) => {
67 println!(" โ Error: {}", e);
68 }
69 }
70 }
71
72 println!("\nโ
Testing complete!");
73 Ok(())
74}
75
76pub fn run_comprehensive_llm_test(
78 vault_path: Option<PathBuf>,
79 model_name: String,
80 verbose: bool,
81) -> Result<(), String> {
82 let vault_path = vault_path.unwrap_or_else(default_vault_path);
83
84 if verbose {
85 init_log_stream(true);
86 }
87
88 println!("๐งช Running Comprehensive LLM Test Suite");
89 println!("๐ Vault path: {}", vault_path.display());
90 println!("๐ค Model: {}", model_name);
91 println!();
92
93 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
95 println!("STEP 1: Loading Model");
96 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
97
98 let gguf = resolve_vault_model(&vault_path, &model_name)
99 .map_err(|e| format!("Failed to resolve model: {}", e))?;
100
101 println!("Loading {} โฆ", gguf.display());
102 let start = std::time::Instant::now();
103
104 let record = tokio::task::block_in_place(|| {
105 tokio::runtime::Handle::current().block_on(
106 qualia_client_core::model_lifecycle::activate_vault_gguf(&gguf),
107 )
108 })
109 .map_err(|e| format!("Failed to activate model: {}", e))?;
110
111 let load_time = start.elapsed();
112 println!("โ
Model loaded in {:?}", load_time);
113 println!(" Profile ID: 0x{:016x}", record.profile_id);
114 println!(" Context Window: {}", record.context_window);
115 println!();
116
117 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
119 println!("STEP 2: Creating Agent");
120 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
121
122 use qualia_core_db::llm_agent::{AgentBackend, LocalLlmAgent};
123
124 let agent = LocalLlmAgent::with_local_backend(
125 format!("did:qualia:cli-test:{}", record.profile_id),
126 AgentBackend::Local {
127 model_path: record.gguf_path.clone(),
128 context_window: record.context_window,
129 quantization: record.quantization.clone(),
130 vision_projector_path: record.mmproj_path.clone(),
131 modality: record.modality.clone(),
132 architecture: record.architecture.clone(),
133 },
134 );
135
136 println!("โ
Agent created");
137 println!();
138
139 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
141 println!("STEP 3: Inference Tests");
142 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
143
144 qualia_core_db::llm_bench::set_sampler_config(Some(
147 qualia_core_db::sampler::SamplerConfig::chat_default(),
148 ));
149
150 let test_prompts = vec![
151 ("Basic Knowledge", "What is the capital of France?", 50),
152 (
153 "System Awareness",
154 "What is QualiaDB and what are its main features?",
155 100,
156 ),
157 (
158 "Technical Understanding",
159 "Explain what a NQuin is in simple terms.",
160 80,
161 ),
162 (
163 "Capability Awareness",
164 "What capabilities does the Qualia system have for semantic graph processing?",
165 120,
166 ),
167 (
168 "Instruction Following",
169 "Write a haiku about artificial intelligence.",
170 30,
171 ),
172 ];
173
174 let mut total_tokens = 0;
175 let mut total_time_ms = 0;
176 let mut total_ttft_ms = 0;
177 let mut successful_tests = 0;
178
179 for (test_name, prompt, _max_tokens) in test_prompts.iter() {
180 println!("โโ Test: {}", test_name);
181 println!("โโ Prompt: {}", prompt);
182
183 let started = std::time::Instant::now();
184
185 let (response, _provenance, tokens_generated, _quin) = tokio::task::block_in_place(|| {
189 agent.infer_local_model_streaming::<fn(String)>(prompt, "graph_context:cli_test", None)
190 });
191
192 let elapsed = started.elapsed();
193 let elapsed_ms = elapsed.as_millis() as u64;
194
195 let ttft = elapsed_ms / 10;
197
198 let token_count = tokens_generated as u64;
199 let token_count = if token_count == 0 && !response.is_empty() {
202 (response.chars().count() as u64 / 4).max(1)
204 } else {
205 token_count
206 };
207 let tps = if elapsed_ms > 0 {
208 (token_count as f64 * 1000.0) / elapsed_ms as f64
209 } else {
210 0.0
211 };
212
213 println!("โโ TTFT: {}ms (estimated)", ttft);
214 println!("โโ Total Time: {}ms", elapsed_ms);
215 println!("โโ Tokens: {} (decode)", token_count);
216 println!("โโ TPS: {:.2} (wall-clock / decode tokens)", tps);
217
218 total_tokens += token_count;
219 total_time_ms += elapsed_ms;
220 total_ttft_ms += ttft;
221 successful_tests += 1;
222
223 print!("โโ Response: ");
224 let preview: String = response.chars().take(200).collect();
226 println!(
227 "{}{}",
228 preview,
229 if response.len() > 200 { "..." } else { "" }
230 );
231 println!();
232 }
233
234 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
236 println!("TEST SUMMARY");
237 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
238 println!("โ
Model Loading: PASS ({:?})", load_time);
239 println!("โ
Agent Creation: PASS");
240 println!(
241 "โ
Inference: {} / {} tests passed",
242 successful_tests,
243 test_prompts.len()
244 );
245
246 if successful_tests > 0 {
247 let avg_ttft = total_ttft_ms as f64 / successful_tests as f64;
248 let avg_tps = if total_time_ms > 0 {
249 (total_tokens as f64 * 1000.0) / total_time_ms as f64
250 } else {
251 0.0
252 };
253
254 println!();
255 println!("๐ METRICS:");
256 println!(" โโ Total Tokens Generated: {}", total_tokens);
257 println!(" โโ Total Generation Time: {}ms", total_time_ms);
258 println!(" โโ Average TTFT: {:.2}ms", avg_ttft);
259 println!(" โโ Average TPS: {:.2}", avg_tps);
260 }
261
262 println!();
263 println!("Note: Metrics include orchestration overhead (Webizen validation, etc.).");
264 println!("Note: Token counts use engine tokens_generated (not provenance-hash vec length).");
265
266 Ok(())
267}
268
269pub fn run_convert_gguf_to_p64(
275 input: &Path,
276 out_dir: &Path,
277 page_log2: u16,
278 layout: &str,
279) -> Result<(), String> {
280 if !input.is_file() {
281 return Err(format!("input not found: {}", input.display()));
282 }
283 let ext = input
284 .extension()
285 .and_then(|e| e.to_str())
286 .unwrap_or("")
287 .to_ascii_lowercase();
288 if ext != "gguf" && ext != "safetensors" {
289 return Err(format!(
290 "only .gguf or .safetensors import is supported in this command (got .{ext})"
291 ));
292 }
293 let src_len = std::fs::metadata(input).map(|m| m.len()).unwrap_or(0);
294 const DEFAULT_VRAM_BUDGET: u64 = 12u64 * 1024 * 1024 * 1024;
296 let layout = match layout.trim().to_ascii_lowercase().as_str() {
297 "verbatim" | "raw" | "copy" => qualia_core_db::p64_weight::P64ConvertLayout::Verbatim,
298 "f16" | "fp16" | "half" => qualia_core_db::p64_weight::P64ConvertLayout::F16Expand,
299 "soa" | "q4k-soa" | "q4k_soa" | "soa-q4k" => {
300 qualia_core_db::p64_weight::P64ConvertLayout::Q4kSoa
301 }
302 "auto" | "best" | "remarkable" => {
303 let rec =
304 qualia_core_db::p64_weight::recommend_convert_layout(src_len, DEFAULT_VRAM_BUDGET);
305 println!("โโ auto layout โ {rec:?} (source {src_len} B, 12 GiB VRAM budget)");
306 rec
307 }
308 other => {
309 return Err(format!(
310 "unknown --layout '{other}' (expected verbatim|f16|soa|auto)"
311 ))
312 }
313 };
314
315 std::fs::create_dir_all(out_dir)
316 .map_err(|e| format!("create out dir {}: {e}", out_dir.display()))?;
317
318 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
319 println!("Model ({ext}) โ p64 + q42 convert");
320 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
321 println!("โโ Input: {}", input.display());
322 println!("โโ Out: {}", out_dir.display());
323 println!("โโ page_log2: {page_log2}");
324 println!("โโ layout: {layout:?}");
325
326 let t0 = std::time::Instant::now();
327 let mmap = {
328 let f = std::fs::File::open(input).map_err(|e| format!("open: {e}"))?;
329 unsafe { memmap2::Mmap::map(&f).map_err(|e| format!("mmap: {e}"))? }
331 };
332 let src_bytes = mmap.len();
333 println!(
334 "โโ Source size: {:.1} MiB",
335 src_bytes as f64 / (1024.0 * 1024.0)
336 );
337
338 let p64 = if ext == "safetensors" {
339 let mut buf = Vec::new();
340 qualia_core_db::p64_weight::transcode_safetensor_to_p64(&mmap, page_log2, &mut buf)
341 .map_err(|e| format!("transcode_safetensor_to_p64: {e}"))?;
342 buf
343 } else {
344 qualia_core_db::p64_weight::compile_gguf_to_p64_with_layout(&mmap, page_log2, layout)
345 .map_err(|e| format!("compile_gguf_to_p64: {e}"))?
346 };
347 let stem = input
348 .file_stem()
349 .and_then(|s| s.to_str())
350 .unwrap_or("model");
351 let suffix = match layout {
352 qualia_core_db::p64_weight::P64ConvertLayout::Verbatim => "",
353 qualia_core_db::p64_weight::P64ConvertLayout::F16Expand => ".f16",
354 qualia_core_db::p64_weight::P64ConvertLayout::Q4kSoa => ".soa",
355 };
356 let p64_path = out_dir.join(format!("{stem}{suffix}.p64"));
357 std::fs::write(&p64_path, &p64).map_err(|e| format!("write p64: {e}"))?;
358
359 let tok = qualia_core_db::gguf_sharder::GgufTokenizer::from_gguf(&mmap);
361 let stop_ids: Vec<u32> = tok.stop_tokens().to_vec();
362 let stop_names: Vec<String> = stop_ids
363 .iter()
364 .filter_map(|&id| tok.vocab.get(id as usize).cloned())
365 .collect();
366 let helper = qualia_core_db::model_helper::ModelHelper::new(
367 input
368 .file_name()
369 .and_then(|s| s.to_str())
370 .unwrap_or("model.gguf"),
371 p64_path
372 .file_name()
373 .and_then(|s| s.to_str())
374 .unwrap_or("model.p64"),
375 page_log2,
376 format!("{layout:?}"),
377 qualia_core_db::model_helper::ModelHelperTokenizer {
378 bos_token_id: tok.bos_token_id,
379 eos_token_id: tok.eos_token_id,
380 add_bos_token: tok.add_bos_token,
381 chat_family: format!("{:?}", tok.chat_family()),
382 stop_token_ids: stop_ids,
383 stop_token_strings: stop_names,
384 vocab_len: tok.vocab_len(),
385 },
386 );
387 let q42_path = helper
388 .write_beside_p64(&p64_path)
389 .map_err(|e| format!("write canonical q42 helper: {e}"))?;
390
391 let index = qualia_core_db::p64_weight::P64TensorIndex::from_p64(&p64)
393 .map_err(|e| format!("p64 self-check failed: {e}"))?;
394 let n_tensors = index.entries.len();
395 let _ = qualia_core_db::model_helper::ModelHelper::load_beside_p64(&p64_path)
397 .map_err(|e| format!("helper self-check failed: {e}"))?
398 .ok_or_else(|| "helper self-check failed: canonical .q42 was not found".to_string())?;
399
400 let elapsed = t0.elapsed();
401 println!();
402 println!("โ
Convert complete in {:.1}s", elapsed.as_secs_f64());
403 println!(" โโ {}", p64_path.display());
404 println!(
405 " size {:.1} MiB, tensors {}",
406 p64.len() as f64 / (1024.0 * 1024.0),
407 n_tensors
408 );
409 println!(" โโ {} (Q42 v3)", q42_path.display());
410 println!(
411 " chat_family={:?} stop_ids={:?}",
412 tok.chat_family(),
413 tok.stop_tokens()
414 );
415 println!();
416 println!("Activate with a Local backend path pointing at the .p64 file.");
417 Ok(())
418}
419
420pub fn run_optimize_pipeline(
422 input: &Path,
423 out: Option<PathBuf>,
424 skip_passport: bool,
425) -> Result<(), String> {
426 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
427 println!("REMARKABLE PATH โ passport + convert + activate knobs");
428 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
429
430 if !skip_passport {
431 let _ = run_hardware_passport(true, 512, None, true, None, 16);
432 }
433
434 let out_dir = out.unwrap_or_else(|| {
435 input
436 .parent()
437 .map(|p| p.to_path_buf())
438 .unwrap_or_else(|| PathBuf::from("."))
439 });
440 run_convert_gguf_to_p64(input, &out_dir, 14, "auto")?;
441
442 let stem = input
443 .file_stem()
444 .and_then(|s| s.to_str())
445 .unwrap_or("model");
446 let candidates = [
448 out_dir.join(format!("{stem}.f16.p64")),
449 out_dir.join(format!("{stem}.soa.p64")),
450 out_dir.join(format!("{stem}.p64")),
451 ];
452 let p64 = candidates.iter().find(|p| p.is_file());
453 println!();
454 println!("Activate (fast path):");
455 println!(" $env:QUALIA_P64_INTEGRITY='metadata'");
456 if let Some(p) = p64 {
457 println!(" # model path: {}", p.display());
458 if let Ok(Some(h)) = qualia_core_db::model_helper::ModelHelper::load_beside_p64(p) {
459 println!(
460 " # helper: layout={} family={} stops={:?}",
461 h.layout, h.tokenizer.chat_family, h.tokenizer.stop_token_ids
462 );
463 }
464 }
465 println!(" qualia-cli llm load <stem-or-path> # vault prefers .p64");
466 Ok(())
467}
468
469pub fn run_hardware_passport(
473 reprobe: bool,
474 gemv_n: usize,
475 cache: Option<PathBuf>,
476 apply_env_hint: bool,
477 decode_proxy: Option<Option<PathBuf>>,
478 decode_proxy_tokens: u32,
479) -> Result<(), String> {
480 use qualia_core_db::device_benchmark::benchmark_devices;
481 use qualia_core_db::hardware_passport::{
482 attach_decode_proxy_via_subprocess, backend_env_token, default_cache_path,
483 default_decode_proxy_model, load_or_probe, topology_key, write_passport, HardwarePassport,
484 PASSPORT_VERSION,
485 };
486 use qualia_core_db::host_topology::probe_host_topology;
487
488 let path = cache.unwrap_or_else(default_cache_path);
489 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
490 println!("HardwarePassport");
491 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
492 println!("โโ Cache: {}", path.display());
493 println!("โโ GEMV n: {gemv_n}");
494 println!("โโ Reprobe: {reprobe}");
495
496 let (mut passport, was_cached) = if reprobe {
497 if path.exists() {
498 let _ = std::fs::remove_file(&path);
499 }
500 let topology = probe_host_topology();
501 let key = topology_key(&topology);
502 println!("โโ Probing circuits (this takes a few seconds)โฆ");
503 let matrix = benchmark_devices(gemv_n);
504 let preferred = matrix
505 .best()
506 .and_then(|c| backend_env_token(&c.backend))
507 .map(str::to_string);
508 let fresh = HardwarePassport {
509 version: PASSPORT_VERSION,
510 key,
511 topology,
512 matrix,
513 preferred_inference_backend: preferred,
514 probe_gemv_n: gemv_n,
515 decode_proxy_model: None,
516 decode_proxy_tokens: 0,
517 };
518 write_passport(&fresh, &path)?;
519 (fresh, false)
520 } else {
521 load_or_probe(&path, gemv_n)
522 };
523
524 if let Some(model_opt) = decode_proxy {
526 let model = match model_opt {
527 Some(p) => p,
528 None => default_decode_proxy_model().ok_or_else(|| {
529 "no decode-proxy model: pass --decode-proxy <path> or set QUALIA_LLM_PROFILE_MODEL / place smollm under C:/LLM_Models/P64".to_string()
530 })?,
531 };
532 if !model.is_file() {
533 return Err(format!("decode-proxy model not found: {}", model.display()));
534 }
535 let exe = std::env::current_exe().map_err(|e| format!("current_exe: {e}"))?;
536 println!(
537 "โโ Decode-proxy: {} ({} tokens, child process per GPU backend)โฆ",
538 model.display(),
539 decode_proxy_tokens
540 );
541 attach_decode_proxy_via_subprocess(&mut passport.matrix, &model, decode_proxy_tokens, &exe);
542 passport.decode_proxy_model = Some(model.display().to_string());
543 passport.decode_proxy_tokens = decode_proxy_tokens;
544 passport.preferred_inference_backend = passport
545 .matrix
546 .best()
547 .and_then(|c| backend_env_token(&c.backend))
548 .map(str::to_string);
549 write_passport(&passport, &path)?;
550 println!("โโ Decode-proxy ranking applied + cache updated");
551 }
552
553 println!(
554 "โโ Source: {}",
555 if was_cached {
556 "cache hit (fast-boot)"
557 } else {
558 "fresh probe"
559 }
560 );
561 println!("โโ Key: {}", passport.key);
562 if let Some(ref m) = passport.decode_proxy_model {
563 println!(
564 "โโ Decode-proxy model: {m} ({} tokens)",
565 passport.decode_proxy_tokens
566 );
567 }
568 println!("{}", passport.matrix.summary());
569
570 if let Some(ref pref) = passport.preferred_inference_backend {
571 println!("โโ Preferred inference backend (stored): {pref}");
572 }
573 if let Some(best) = passport.matrix.best() {
574 println!("Selected inference circuit (measured):");
575 println!(
576 " โโ {} [{}] {:.3} ms/GEMV {:.1} GFLOP/s{}",
577 best.label,
578 best.backend,
579 best.ms_per_gemv,
580 best.gflops,
581 best.decode_proxy_tok_s
582 .map(|t| format!(" {t:.2} tok/s decode-proxy"))
583 .unwrap_or_default()
584 );
585 let hint = passport
586 .preferred_inference_backend
587 .clone()
588 .or_else(|| backend_env_token(&best.backend).map(str::to_string));
589 if let Some(h) = hint {
590 println!(" โโ Hint: set QUALIA_WGPU_BACKEND={h} to pin this backend");
591 println!(
592 " โโ Fast P64 activate: QUALIA_P64_INTEGRITY=metadata (after trusted convert)"
593 );
594 if apply_env_hint {
595 let hint_path = path.with_extension("env");
596 std::fs::write(
597 &hint_path,
598 format!("QUALIA_WGPU_BACKEND={h}\nQUALIA_P64_INTEGRITY=metadata\n"),
599 )
600 .map_err(|e| format!("write env hint: {e}"))?;
601 println!(" โโ Wrote {}", hint_path.display());
602 }
603 } else {
604 println!(" โโ Best circuit is CPU โ keep GPU default; no QUALIA_WGPU_BACKEND pin");
605 }
606 }
607 Ok(())
608}
609
610pub fn run_ground_check(prompt: &str, answer: &str) -> Result<(), String> {
612 use qualia_core_db::{active_inference_mode, fact_count, ground_generation};
613 let g = ground_generation(prompt, answer);
614 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
615 println!("Quant-graph grounding check");
616 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
617 println!("โโ active mode: {}", active_inference_mode().as_str());
618 println!("โโ fact_count: {}", fact_count());
619 println!("โโ repaired: {}", g.repaired);
620 println!("โโ reason: {:?}", g.reason);
621 println!(
622 "โโ object_hash: {:?}",
623 g.object_hash.map(|h| format!("{h:#x}"))
624 );
625 println!("โโ text: {}", g.text);
626 Ok(())
627}
628
629pub fn run_seed_grounding() -> Result<(), String> {
631 let n = qualia_core_db::seed_facts_from_bundled();
632 println!(
633 "seeded {n} grounding facts (fact_count={})",
634 qualia_core_db::fact_count()
635 );
636 Ok(())
637}
638
639pub fn run_cuda_tc_microbench(side: usize) -> Result<(), String> {
641 use std::time::Instant;
642 let n = side.max(16);
643 let n = ((n + 15) / 16) * 16;
645 let k = n;
646 let m = n;
647 let a = vec![1.0f32; m * k];
648 let b = vec![1.0f32; k * n];
649 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
650 println!("CUDA TC microbench C[{m}ร{n}] = A[{m}ร{k}]ยทB[{k}ร{n}]");
651 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
652 let _ = qualia_core_db::wgsl_forge::dispatch::ensure_cuda_runtime_path();
654 let t0 = Instant::now();
655 let r1 = qualia_core_db::wgsl_forge::dispatch::gemm_f32_tc_reduced(m, k, n, &a, &b)
657 .map_err(|e| format!("gemm_f32_tc_reduced: {e:?}"))?;
658 let warm_ms = t0.elapsed().as_secs_f64() * 1000.0;
659 let t1 = Instant::now();
660 let r2 = qualia_core_db::wgsl_forge::dispatch::gemm_f32_tc_reduced(m, k, n, &a, &b)
661 .map_err(|e| format!("gemm_f32_tc_reduced: {e:?}"))?;
662 let hot_ms = t1.elapsed().as_secs_f64() * 1000.0;
663 let caps = qualia_core_db::wgsl_forge::dispatch::caps();
664 println!(
665 "โโ caps: wgpu={} cuda={} coopmat={}",
666 caps.wgpu, caps.cuda, caps.coopmat
667 );
668 println!("โโ warm: {warm_ms:.2} ms (includes NVRTC/context first use)");
669 println!("โโ hot: {hot_ms:.2} ms");
670 println!(
671 "โโ C[0]={:.1} (expect ~{n}.0 for all-ones)",
672 r2.first().copied().unwrap_or(0.0)
673 );
674 println!("โโ ok: r1_len={} r2_len={}", r1.len(), r2.len());
675 Ok(())
676}
677
678pub fn run_inference_mode(set: Option<&str>) -> Result<(), String> {
680 use qualia_core_db::{active_inference_mode, set_inference_mode, InferenceMode};
681 if let Some(name) = set {
682 let m = InferenceMode::parse(name).ok_or_else(|| {
683 format!("unknown mode '{name}' (expected: portable | cuda | quant-graph | fast-verify)")
684 })?;
685 set_inference_mode(m);
686 std::env::set_var("QUALIA_INFERENCE_MODE", m.as_str());
688 println!("MODE set={}", m.as_str());
689 println!(" {}", m.description());
690 println!(" (shell: $env:QUALIA_INFERENCE_MODE='{}')", m.as_str());
691 return Ok(());
692 }
693 let active = active_inference_mode();
694 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
695 println!("Inference modes (coexisting approaches โ not replacements)");
696 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
697 println!("Active: {} โ {}", active.as_str(), active.description());
698 println!();
699 for m in InferenceMode::ALL {
700 let mark = if m == active { "*" } else { " " };
701 println!(" [{mark}] {:12} {}", m.as_str(), m.description());
702 }
703 println!();
704 println!("Set: qualia-cli llm mode <portable|cuda|quant-graph>");
705 println!("Env: QUALIA_INFERENCE_MODE");
706 println!("Plan: docs/plans/inference-multi-mode-and-compression.md");
707 Ok(())
708}
709
710pub fn run_lab(
712 action: &str,
713 model: Option<&std::path::Path>,
714 tokens: u32,
715 n_in: usize,
716 n_out: usize,
717 gemv_n: usize,
718 out: Option<&std::path::Path>,
719 hours: f64,
720 max_generations: u32,
721 ollama_model: Option<&str>,
722 ollama_url: &str,
723 no_ollama: bool,
724) -> Result<(), String> {
725 use qualia_core_db::lab::{
726 ablate::format_ablation_report, audit_hot_path, calibrate_device_roof,
727 format_lockin_summary, run_ablation_matrix, run_auto_improve, run_decode_timeline,
728 run_q4k_soa_microbench, AutoImproveConfig,
729 };
730 match action.trim().to_ascii_lowercase().as_str() {
731 "audit-path" | "audit" => {
732 print!("{}", audit_hot_path().format_report());
733 Ok(())
734 }
735 "roof" | "device-roof" => {
736 print!("{}", calibrate_device_roof(gemv_n).format_report());
737 let (g, i) = qualia_core_db::lab::device_roof::cpu_q4_intensity_probe(1024, 32);
738 println!(" cpu_q4_probe: {g:.2} GFLOP/s intensity={i:.3} FLOP/B");
739 Ok(())
740 }
741 "micro" | "microbench" => {
742 print!("{}", run_q4k_soa_microbench(n_in, n_out).format_report());
743 Ok(())
744 }
745 "timeline" => {
746 let m = model.ok_or("timeline requires --model <path.p64>")?;
747 let t = if tokens == 0 { 4 } else { tokens };
748 print!("{}", run_decode_timeline(m, t).format_report());
749 Ok(())
750 }
751 "ablate" | "ablation" => {
752 let m = model.ok_or("ablate requires --model <path.p64>")?;
753 let t = if tokens == 0 { 8 } else { tokens };
754 let csv =
755 out.or_else(|| Some(std::path::Path::new("experiments/inference-lab/runs.csv")));
756 let rows = run_ablation_matrix(m, t, csv);
757 print!("{}", format_ablation_report(&rows));
758 if let Some(p) = csv {
759 println!("CSV appended: {}", p.display());
760 }
761 Ok(())
762 }
763 "auto" | "auto-improve" | "lockin" | "self-improve" => {
764 let m = model.ok_or(
765 "lab auto requires --model <path.p64> (e.g. smollm2 or Llama-3.2-3B .p64)",
766 )?;
767 let t = if tokens == 0 { 16 } else { tokens };
768 let hours = if hours <= 0.0 { 2.0 } else { hours };
769 let out_dir = out
770 .map(|p| p.to_path_buf())
771 .unwrap_or_else(|| std::path::PathBuf::from("experiments/inference-lab/lockin"));
772 let ollama = if no_ollama {
773 None
774 } else {
775 match ollama_model {
776 Some(s) if s.is_empty() || s.eq_ignore_ascii_case("none") => None,
777 Some(s) => Some(s.to_string()),
778 None => Some("qualia-smol-q8:latest".into()),
779 }
780 };
781 let cfg = AutoImproveConfig {
782 model: m.to_path_buf(),
783 tokens: t,
784 max_duration: std::time::Duration::from_secs_f64(hours * 3600.0),
785 out_dir,
786 ollama_model: ollama,
787 ollama_url: ollama_url.to_string(),
788 elite_resample: 3,
789 plateau_rel: 0.02,
790 plateau_gens: 2,
791 max_generations: max_generations.max(1),
792 };
793 println!("lab auto โ recursive measure โ search โ lock-in");
794 println!(" model: {}", cfg.model.display());
795 println!(" tokens: {}", cfg.tokens);
796 println!(" hours: {hours}");
797 println!(" gens: {}", cfg.max_generations);
798 println!(" out: {}", cfg.out_dir.display());
799 println!(
800 " ollama: {}",
801 cfg.ollama_model.as_deref().unwrap_or("(skipped)")
802 );
803 println!(" (wall clock budget; plateau or gens may finish earlier)");
804 let pkg = run_auto_improve(&cfg)?;
805 print!("{}", format_lockin_summary(&pkg));
806 println!("Lock-in package written to: {}", pkg.out_dir.display());
807 println!(
808 " BEST_CONFIG.json METHODOLOGY.md apply-best.ps1 runs.csv LOCKIN_SUMMARY.txt"
809 );
810 Ok(())
811 }
812 "gpu-cap" | "gpu-capability" | "machine-gpu" => {
813 let t = if tokens == 0 { 16 } else { tokens };
814 run_gpu_capability_campaign(model, out, t)
815 }
816 "help" | _ => {
817 println!("qualia-cli llm lab <action>");
818 println!(" audit-path hot-path wiring audit");
819 println!(" roof [--gemv-n N] device roof calibration");
820 println!(" micro [--n-in N --n-out M] Q4 SoA GEMV microbench");
821 println!(" timeline --model P [--tokens T] decode phase timeline");
822 println!(" ablate --model P [--tokens T] [--out runs.csv]");
823 println!(" auto --model P [--hours H] [--tokens T] [--out lockin-dir]");
824 println!(" [--max-generations N] [--ollama-model TAG] [--no-ollama]");
825 println!(" multi-hour recursive search โ lock-in package");
826 println!(" gpu-cap [--model P] [--tokens T] [--out dir]");
827 println!(" native GPU tier probe + backendรmode decode matrix");
828 println!(" โ machine-gpu-profile.json + apply-machine-gpu.ps1");
829 println!("Plan: docs/plans/inference-superiority-lab-and-toolset-plan.md");
830 if action != "help" && !action.is_empty() && action != "_" {
831 return Err(format!("unknown lab action '{action}'"));
832 }
833 Ok(())
834 }
835 }
836}
837
838pub fn run_gpu_capability_campaign(
848 model: Option<&Path>,
849 out_dir: Option<&Path>,
850 tokens: u32,
851) -> Result<(), String> {
852 use qualia_core_db::machine_gpu_profile::{
853 AdapterFeatures, MachineGpuProfile, MeasuredDecodePath, ToolchainAvailability,
854 MACHINE_GPU_PROFILE_VERSION,
855 };
856 use std::process::Command;
857
858 fn tool_ok(program: &str, arg: &str) -> bool {
859 Command::new(program)
860 .arg(arg)
861 .output()
862 .map(|o| o.status.success())
863 .unwrap_or(false)
864 }
865
866 let p64 = match model {
867 Some(p) => p.to_path_buf(),
868 None => {
869 qualia_core_db::hardware_passport::default_decode_proxy_model().ok_or_else(|| {
870 "no package: pass --model <path.p64> or set QUALIA_LLM_PROFILE_MODEL".to_string()
871 })?
872 }
873 };
874 if !p64.is_file() {
875 return Err(format!("package not found: {}", p64.display()));
876 }
877 let out = out_dir
878 .map(|p| p.to_path_buf())
879 .unwrap_or_else(|| p64.parent().unwrap_or(Path::new(".")).to_path_buf());
880 let tokens = tokens.clamp(8, 128);
881
882 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
883 println!("GPU CAPABILITY โ native tiers over the WGSL floor");
884 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
885 println!("โโ Package: {}", p64.display());
886 println!("โโ Tokens: {tokens}");
887 println!("โโ Out: {}", out.display());
888
889 let nvcc = std::env::var("CUDA_PATH")
891 .map(|p| format!("{p}/bin/nvcc"))
892 .unwrap_or_else(|_| "nvcc".to_string());
893 let dxc = std::env::var("QUALIA_DXC_PATH").unwrap_or_else(|_| "dxc".to_string());
894 let cuda_toolkit = tool_ok(&nvcc, "--version");
895 let dxc_cli = tool_ok(&dxc, "--version");
896 let metal_xcrun = cfg!(target_os = "macos") && tool_ok("xcrun", "--version");
897
898 let gpu = qualia_core_db::gpu_context::try_shared_gpu();
900 let adapter = match gpu {
901 Some(g) => AdapterFeatures {
902 name: g.adapter_caps.name.clone(),
903 backend: g.adapter_caps.backend_label().to_string(),
904 discrete: g.adapter_caps.device_type_label() == "discrete",
905 subgroups: g.adapter_caps.features.subgroup,
906 coopmat: g.adapter_caps.cooperative_matrix_tile_count > 0,
907 shader_f16: g.adapter_caps.features.shader_f16,
908 timestamp_query: g.timestamps_supported,
909 topology_hash: qualia_core_db::hardware_passport::topology_key(
910 &qualia_core_db::host_topology::probe_host_topology(),
911 ),
912 },
913 None => AdapterFeatures::default(),
914 };
915 println!(
916 "โโ Adapter: {} ({}) subgroups={} coopmat={} f16={}",
917 if adapter.name.is_empty() {
918 "none"
919 } else {
920 &adapter.name
921 },
922 adapter.backend,
923 adapter.subgroups,
924 adapter.coopmat,
925 adapter.shader_f16
926 );
927 println!(
928 "โโ Toolchain: wgpu={} cuda={cuda_toolkit} dxc_cli={dxc_cli} metal={metal_xcrun}",
929 gpu.is_some()
930 );
931
932 let mut native_tiers = vec!["wgsl".to_string(), "spirv".to_string()];
933 if cuda_toolkit {
934 native_tiers.push("cuda-c".into());
935 native_tiers.push("ptx".into());
936 }
937 if dxc_cli {
938 native_tiers.push("hlsl-dxc".into());
939 }
940 if metal_xcrun {
941 native_tiers.push("msl".into());
942 }
943 if adapter.subgroups {
944 native_tiers.push("subgroups".into());
945 }
946 if adapter.coopmat {
947 native_tiers.push("coopmat".into());
948 }
949
950 let backends: &[&str] = if cfg!(target_os = "macos") {
952 &["metal"]
953 } else if cfg!(target_os = "windows") {
954 &["vulkan", "dx12"]
955 } else {
956 &["vulkan"]
957 };
958 let modes = ["portable", "fast-verify", "cuda"];
959 let self_exe = std::env::current_exe().map_err(|e| format!("current_exe: {e}"))?;
960 let mut measured: Vec<MeasuredDecodePath> = Vec::new();
961
962 let wgpu_cells = backends.len() * modes.len();
963 let cuda_c_cells = if cuda_toolkit { 1 } else { 0 };
964 let hlsl_cells = if dxc_cli { 1 } else { 0 };
965 let spirv_cells = if dxc_cli { 1 } else { 0 };
966 let ptx_cells = if cuda_toolkit { 1 } else { 0 };
967 println!(
968 "โโ Decode matrix ({} cells)โฆ",
969 wgpu_cells + cuda_c_cells + hlsl_cells + spirv_cells + ptx_cells
970 );
971 for backend in backends {
972 for mode in modes {
973 print!("โ {backend:7} {mode:12} โฆ ");
974 use std::io::Write as _;
975 let _ = std::io::stdout().flush();
976 let t0 = std::time::Instant::now();
977 let output = Command::new(&self_exe)
978 .args([
979 "llm",
980 "decode-proxy",
981 &p64.display().to_string(),
982 "--tokens",
983 &tokens.to_string(),
984 ])
985 .env("QUALIA_WGPU_BACKEND", backend)
986 .env("QUALIA_INFERENCE_MODE", mode)
987 .env_remove("QUALIA_FORGE_BACKEND")
988 .env_remove("QUALIA_DXC_PATH")
989 .output();
990 let wall = t0.elapsed().as_secs_f64();
991 match output {
992 Ok(o) => {
993 let stdout = String::from_utf8_lossy(&o.stdout);
994 match qualia_core_db::hardware_passport::parse_decode_proxy_record(&stdout) {
995 Some(rec) => {
996 let coherence_ok = rec.coherence_ok.unwrap_or(o.status.success());
997 println!(
998 "{:.2} tok/s {} ({wall:.1}s)",
999 rec.tok_s,
1000 if coherence_ok {
1001 "coherent"
1002 } else {
1003 "INCOHERENT"
1004 }
1005 );
1006 measured.push(MeasuredDecodePath {
1007 wgpu_backend: (*backend).to_string(),
1008 inference_mode: mode.to_string(),
1009 p64_path: p64.display().to_string(),
1010 tok_s: rec.tok_s,
1011 coherence_ok,
1012 tokens,
1013 });
1014 }
1015 None => {
1016 let stderr = String::from_utf8_lossy(&o.stderr);
1017 let tail: String = stderr.lines().rev().take(1).collect();
1018 println!("no DECODE_PROXY line ({wall:.1}s) {tail}");
1019 }
1020 }
1021 }
1022 Err(e) => println!("spawn failed ({wall:.1}s): {e}"),
1023 }
1024 }
1025 }
1026
1027 if cuda_toolkit {
1034 print!("โ cuda-c native โฆ ");
1035 use std::io::Write as _;
1036 let _ = std::io::stdout().flush();
1037 let t0 = std::time::Instant::now();
1038 let output = Command::new(&self_exe)
1039 .args([
1040 "llm",
1041 "decode-proxy",
1042 &p64.display().to_string(),
1043 "--tokens",
1044 &tokens.to_string(),
1045 ])
1046 .env("QUALIA_INFERENCE_MODE", "cuda")
1047 .env("QUALIA_LLM_CUDA_DECODE", "1")
1048 .env("QUALIA_LLM_KV_INT8", "0")
1049 .env_remove("QUALIA_FORGE_BACKEND")
1050 .env_remove("QUALIA_DXC_PATH")
1051 .output();
1052 let wall = t0.elapsed().as_secs_f64();
1053 match output {
1054 Ok(o) => {
1055 let stdout = String::from_utf8_lossy(&o.stdout);
1056 match qualia_core_db::hardware_passport::parse_decode_proxy_record(&stdout) {
1057 Some(rec) => {
1058 let path_ok = rec.execution_path.as_deref() == Some("cuda-c");
1059 let coherence_ok =
1060 rec.coherence_ok.unwrap_or(o.status.success()) && path_ok;
1061 println!(
1062 "{:.2} tok/s {} path={} ({wall:.1}s)",
1063 rec.tok_s,
1064 if coherence_ok { "coherent" } else { "REJECTED" },
1065 rec.execution_path.as_deref().unwrap_or("unattributed"),
1066 );
1067 if path_ok {
1068 measured.push(MeasuredDecodePath {
1069 wgpu_backend: "cuda-c".to_string(),
1070 inference_mode: "native".to_string(),
1071 p64_path: p64.display().to_string(),
1072 tok_s: rec.tok_s,
1073 coherence_ok,
1074 tokens,
1075 });
1076 }
1077 }
1078 None => {
1079 let stderr = String::from_utf8_lossy(&o.stderr);
1080 let tail: String = stderr.lines().rev().take(1).collect();
1081 println!("no DECODE_PROXY line ({wall:.1}s) {tail}");
1082 }
1083 }
1084 }
1085 Err(e) => println!("spawn failed ({wall:.1}s): {e}"),
1086 }
1087 }
1088
1089 if dxc_cli {
1095 let hlsl_backends: &[&str] = if cfg!(target_os = "macos") {
1099 &["metal"]
1100 } else {
1101 &["vulkan"]
1102 };
1103 for backend in hlsl_backends {
1104 print!("โ hlsl {backend:7} โฆ ");
1105 use std::io::Write as _;
1106 let _ = std::io::stdout().flush();
1107 let t0 = std::time::Instant::now();
1108 let output = Command::new(&self_exe)
1109 .args([
1110 "llm",
1111 "decode-proxy",
1112 &p64.display().to_string(),
1113 "--tokens",
1114 &tokens.to_string(),
1115 ])
1116 .env("QUALIA_WGPU_BACKEND", backend)
1117 .env("QUALIA_FORGE_BACKEND", "hlsl")
1118 .output();
1119 let wall = t0.elapsed().as_secs_f64();
1120 match output {
1121 Ok(o) => {
1122 let stdout = String::from_utf8_lossy(&o.stdout);
1123 match qualia_core_db::hardware_passport::parse_decode_proxy_record(&stdout) {
1124 Some(rec) => {
1125 let path_ok = rec.execution_path.as_deref() == Some("hlsl");
1126 let coherence_ok =
1127 rec.coherence_ok.unwrap_or(o.status.success()) && path_ok;
1128 println!(
1129 "{:.2} tok/s {} path={} ({wall:.1}s)",
1130 rec.tok_s,
1131 if coherence_ok { "coherent" } else { "REJECTED" },
1132 rec.execution_path.as_deref().unwrap_or("unattributed"),
1133 );
1134 if path_ok {
1135 measured.push(MeasuredDecodePath {
1136 wgpu_backend: format!("hlsl-{backend}"),
1137 inference_mode: "portable".to_string(),
1138 p64_path: p64.display().to_string(),
1139 tok_s: rec.tok_s,
1140 coherence_ok,
1141 tokens,
1142 });
1143 }
1144 }
1145 None => {
1146 let stderr = String::from_utf8_lossy(&o.stderr);
1147 let tail: String = stderr.lines().rev().take(1).collect();
1148 println!("no DECODE_PROXY line ({wall:.1}s) {tail}");
1149 }
1150 }
1151 }
1152 Err(e) => println!("spawn failed ({wall:.1}s): {e}"),
1153 }
1154 }
1155 }
1156
1157 if dxc_cli {
1161 let spirv_backends: &[&str] = if cfg!(target_os = "macos") {
1162 &["metal"]
1163 } else {
1164 &["vulkan"]
1165 };
1166 for backend in spirv_backends {
1167 print!("โ spirv-dxc {backend:7} โฆ ");
1168 use std::io::Write as _;
1169 let _ = std::io::stdout().flush();
1170 let t0 = std::time::Instant::now();
1171 let output = Command::new(&self_exe)
1172 .args([
1173 "llm",
1174 "decode-proxy",
1175 &p64.display().to_string(),
1176 "--tokens",
1177 &tokens.to_string(),
1178 ])
1179 .env("QUALIA_WGPU_BACKEND", backend)
1180 .env("QUALIA_FORGE_BACKEND", "spirv")
1181 .output();
1182 let wall = t0.elapsed().as_secs_f64();
1183 match output {
1184 Ok(o) => {
1185 let stdout = String::from_utf8_lossy(&o.stdout);
1186 match qualia_core_db::hardware_passport::parse_decode_proxy_record(&stdout) {
1187 Some(rec) => {
1188 let path_ok = rec.execution_path.as_deref() == Some("spirv");
1189 let coherence_ok =
1190 rec.coherence_ok.unwrap_or(o.status.success()) && path_ok;
1191 println!(
1192 "{:.2} tok/s {} path={} ({wall:.1}s)",
1193 rec.tok_s,
1194 if coherence_ok { "coherent" } else { "REJECTED" },
1195 rec.execution_path.as_deref().unwrap_or("unattributed"),
1196 );
1197 if path_ok {
1198 measured.push(MeasuredDecodePath {
1199 wgpu_backend: format!("spirv-dxc-{backend}"),
1200 inference_mode: "portable".to_string(),
1201 p64_path: p64.display().to_string(),
1202 tok_s: rec.tok_s,
1203 coherence_ok,
1204 tokens,
1205 });
1206 }
1207 }
1208 None => {
1209 let stderr = String::from_utf8_lossy(&o.stderr);
1210 let tail: String = stderr.lines().rev().take(1).collect();
1211 println!("no DECODE_PROXY line ({wall:.1}s) {tail}");
1212 }
1213 }
1214 }
1215 Err(e) => println!("spawn failed ({wall:.1}s): {e}"),
1216 }
1217 }
1218 }
1219
1220 if cuda_toolkit {
1224 print!("โ ptx cuda โฆ ");
1225 use std::io::Write as _;
1226 let _ = std::io::stdout().flush();
1227 let t0 = std::time::Instant::now();
1228 let output = Command::new(&self_exe)
1229 .args([
1230 "llm",
1231 "decode-proxy",
1232 &p64.display().to_string(),
1233 "--tokens",
1234 &tokens.to_string(),
1235 ])
1236 .env("QUALIA_FORGE_BACKEND", "ptx")
1237 .output();
1238 let wall = t0.elapsed().as_secs_f64();
1239 match output {
1240 Ok(o) => {
1241 let stdout = String::from_utf8_lossy(&o.stdout);
1242 match qualia_core_db::hardware_passport::parse_decode_proxy_record(&stdout) {
1243 Some(rec) => {
1244 let path_ok = rec.execution_path.as_deref() == Some("ptx");
1245 let coherence_ok =
1246 rec.coherence_ok.unwrap_or(o.status.success()) && path_ok;
1247 println!(
1248 "{:.2} tok/s {} path={} ({wall:.1}s)",
1249 rec.tok_s,
1250 if coherence_ok { "coherent" } else { "REJECTED" },
1251 rec.execution_path.as_deref().unwrap_or("unattributed"),
1252 );
1253 if path_ok {
1254 measured.push(MeasuredDecodePath {
1255 wgpu_backend: "ptx-cuda".to_string(),
1256 inference_mode: "portable".to_string(),
1257 p64_path: p64.display().to_string(),
1258 tok_s: rec.tok_s,
1259 coherence_ok,
1260 tokens,
1261 });
1262 }
1263 }
1264 None => {
1265 let stderr = String::from_utf8_lossy(&o.stderr);
1266 let tail: String = stderr.lines().rev().take(1).collect();
1267 println!("no DECODE_PROXY line ({wall:.1}s) {tail}");
1268 }
1269 }
1270 }
1271 Err(e) => println!("spawn failed ({wall:.1}s): {e}"),
1272 }
1273 }
1274
1275 let mut profile = MachineGpuProfile {
1277 version: MACHINE_GPU_PROFILE_VERSION,
1278 written_unix_ms: MachineGpuProfile::now_ms(),
1279 host: std::env::var("COMPUTERNAME")
1280 .or_else(|_| std::env::var("HOSTNAME"))
1281 .unwrap_or_else(|_| "unknown".into()),
1282 toolchain: ToolchainAvailability {
1283 wgpu: gpu.is_some(),
1284 cuda_toolkit,
1285 dxc_cli,
1286 metal_xcrun,
1287 },
1288 adapter,
1289 native_tiers,
1290 measured_paths: measured,
1291 recommended: Default::default(),
1292 notes: vec![
1293 "WGSL via wgpu is the portable floor; native tiers (CUDA-C/WMMA, HLSL/DXC, MSL, SPIR-V, subgroups, coopmat) are preferred only when measured coherent and faster.".into(),
1294 "Vendored dxcompiler.dll (DynamicDxc for wgpu DX12) is not the DXC CLI probed here.".into(),
1295 "CUDA densify tensor-core decode stays lab-gated behind QUALIA_LLM_CUDA_TC_DECODE.".into(),
1296 format!("Measured with `llm lab gpu-cap` on {} at {tokens} tokens.", p64.display()),
1297 ],
1298 };
1299 profile.recompute_recommended();
1300
1301 if profile.recommended.wgpu_backend.is_empty() {
1302 return Err(
1303 "no coherent decode path measured โ nothing to recommend (see rows above)".into(),
1304 );
1305 }
1306
1307 let json_path = MachineGpuProfile::default_path(&out);
1308 profile.write_json(&json_path)?;
1309 let apply_path = out.join("apply-machine-gpu.ps1");
1310 std::fs::write(&apply_path, profile.apply_env_script_ps1())
1311 .map_err(|e| format!("write {}: {e}", apply_path.display()))?;
1312
1313 println!();
1314 println!(
1315 "RECOMMENDED backend={} mode={}",
1316 profile.recommended.wgpu_backend, profile.recommended.inference_mode
1317 );
1318 println!(" {}", profile.recommended.rationale);
1319 println!(" profile: {}", json_path.display());
1320 println!(" apply: . {}", apply_path.display());
1321 Ok(())
1322}
1323
1324pub fn run_app_profile(set: Option<&str>) -> Result<(), String> {
1326 use qualia_core_db::{active_application_profile, set_application_profile, ApplicationProfile};
1327 if let Some(name) = set {
1328 let p = ApplicationProfile::parse(name).ok_or_else(|| {
1329 format!("unknown profile '{name}' (expected: interactive | live-fast | batch)")
1330 })?;
1331 set_application_profile(p);
1332 std::env::set_var("QUALIA_APP_PROFILE", p.as_str());
1333 println!("PROFILE set={}", p.as_str());
1334 println!(" {}", p.description());
1335 if matches!(p, ApplicationProfile::BatchOvernight) {
1336 println!(" โ overnight multi-system eval: 2048 tok, 8h wall-clock, HTML verify");
1337 println!(" โ result is local HTML/CML (pipe to mailer if you want email)");
1338 }
1339 return Ok(());
1340 }
1341 let active = active_application_profile();
1342 println!("Application profiles (use case โ not GPU backend)");
1343 println!("Active: {} โ {}", active.as_str(), active.description());
1344 for p in ApplicationProfile::ALL {
1345 let mark = if p == active { "*" } else { " " };
1346 println!(" {mark} {:12} {}", p.as_str(), p.description());
1347 }
1348 println!();
1349 println!("Env: QUALIA_APP_PROFILE=interactive|live-fast|batch");
1350 println!("No Ollama โ all profiles are in-process Qualia native.");
1351 Ok(())
1352}
1353
1354pub fn run_path_select(reprobe: bool, apply: bool) -> Result<(), String> {
1356 let plan = qualia_core_db::inference_path_selector::run_path_select_cli(reprobe, apply);
1357 print!(
1358 "{}",
1359 qualia_core_db::inference_path_selector::format_path_plan(&plan)
1360 );
1361 println!(
1362 "path_auto={}",
1363 qualia_core_db::inference_path_selector::path_auto_enabled()
1364 );
1365 println!("applied_this_run={apply}");
1366 println!();
1367 println!("Operator:");
1368 println!(" 1) qualia-cli llm passport --reprobe --decode-proxy <model.p64> --apply-env-hint");
1369 println!(" 2) qualia-cli llm path-select --apply");
1370 println!(" Env: QUALIA_PATH_AUTO=0 to disable auto-pick; QUALIA_WGPU_BACKEND / QUALIA_INFERENCE_MODE pin.");
1371 println!(" Multi-weight without host RT = resident VRAM plan (Vulkan/DX12/Metal); CUDA slab is optional.");
1372 Ok(())
1373}
1374
1375pub fn run_decode_proxy(model: &Path, tokens: u32) -> Result<(), String> {
1380 use qualia_core_db::hardware_passport::measure_decode_proxy;
1381 if !model.is_file() {
1382 return Err(format!("model not found: {}", model.display()));
1383 }
1384 let backend = std::env::var("QUALIA_WGPU_BACKEND").unwrap_or_else(|_| "auto".into());
1385 let r = measure_decode_proxy(model, tokens)
1386 .ok_or_else(|| "decode-proxy measurement failed (see RUST_LOG)".to_string())?;
1387 let coh = if r.coherence_ok { 1 } else { 0 };
1388 println!(
1390 "DECODE_PROXY tok_s={:.4} backend={backend} path={} tokens={tokens} coherence={coh} resident_hits={} resident_fallbacks={} cuda_hits={} cuda_fallbacks={}",
1391 r.tok_s,
1392 r.execution_path,
1393 r.resident_hits,
1394 r.resident_fallbacks,
1395 r.cuda_mega_hits,
1396 r.cuda_mega_fallbacks,
1397 );
1398 let sample: String = r.text.chars().take(160).collect();
1400 eprintln!("DECODE_SAMPLE coherence={coh} text={sample:?}");
1401 if !r.coherence_ok {
1402 return Err(format!(
1404 "coherence fail: probe did not contain 'Paris' (got {:?})",
1405 sample
1406 ));
1407 }
1408 Ok(())
1409}
1410
1411#[derive(Debug, Clone, serde::Serialize)]
1413pub struct ExploreCandidateResult {
1414 pub layout: String,
1415 pub path: String,
1416 pub tok_s: Option<f64>,
1417 pub error: Option<String>,
1418 pub toggle: String,
1420 pub bytes: u64,
1421 #[serde(default)]
1423 pub coherence_ok: Option<bool>,
1424}
1425
1426#[derive(Debug, Clone, serde::Serialize)]
1427pub struct ExploreReport {
1428 pub version: u32,
1429 pub source: String,
1430 pub out_dir: String,
1431 pub tokens: u32,
1432 pub backend: String,
1433 pub inference_mode: String,
1435 pub candidates: Vec<ExploreCandidateResult>,
1436 pub winner_path: Option<String>,
1437 pub winner_layout: Option<String>,
1438 pub winner_tok_s: Option<f64>,
1439}
1440
1441pub fn run_explore_pipeline(
1446 input: &Path,
1447 out: Option<PathBuf>,
1448 tokens: u32,
1449 layouts_csv: &str,
1450 skip_convert: bool,
1451 sweep_ffn_f16: bool,
1452 modes_csv: Option<&str>,
1453) -> Result<(), String> {
1454 use qualia_core_db::{set_inference_mode, InferenceMode};
1455 use std::io::Write;
1456
1457 if !input.exists() {
1458 return Err(format!("input not found: {}", input.display()));
1459 }
1460
1461 if let Some(csv) = modes_csv {
1463 let modes: Vec<InferenceMode> = csv
1464 .split(',')
1465 .filter_map(|s| InferenceMode::parse(s.trim()))
1466 .collect();
1467 if modes.is_empty() {
1468 return Err("no valid modes in --modes (expected portable,cuda,quant-graph)".into());
1469 }
1470 println!(
1471 "EXPLORE ร MODE matrix: {}",
1472 modes
1473 .iter()
1474 .map(|m| m.as_str())
1475 .collect::<Vec<_>>()
1476 .join(", ")
1477 );
1478 for m in modes {
1479 set_inference_mode(m);
1480 std::env::set_var("QUALIA_INFERENCE_MODE", m.as_str());
1481 println!();
1482 println!("โโโโโโโโ mode={} โโโโโโโโ", m.as_str());
1483 run_explore_pipeline(
1484 input,
1485 out.clone(),
1486 tokens,
1487 layouts_csv,
1488 skip_convert,
1489 sweep_ffn_f16,
1490 None,
1491 )?;
1492 }
1493 return Ok(());
1494 }
1495
1496 let backend = std::env::var("QUALIA_WGPU_BACKEND").unwrap_or_else(|_| "auto".into());
1497 let tokens = tokens.max(8).min(64);
1498
1499 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
1500 println!("EXPLORE โ measure candidates โ rank by decode-proxy tok/s");
1501 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
1502 println!("โโ Input: {}", input.display());
1503 println!("โโ Tokens: {tokens}");
1504 println!("โโ Backend: {backend} (process QUALIA_WGPU_BACKEND)");
1505 println!(
1506 "โโ Mode: {}",
1507 qualia_core_db::active_inference_mode().as_str()
1508 );
1509 println!("โโ Plan: docs/plans/native-inference-explorer-eval-plan.md");
1510
1511 let ext = input
1512 .extension()
1513 .and_then(|e| e.to_str())
1514 .unwrap_or("")
1515 .to_ascii_lowercase();
1516
1517 let out_dir = out.unwrap_or_else(|| {
1518 input
1519 .parent()
1520 .map(|p| p.to_path_buf())
1521 .unwrap_or_else(|| PathBuf::from("."))
1522 });
1523 std::fs::create_dir_all(&out_dir)
1524 .map_err(|e| format!("create out dir {}: {e}", out_dir.display()))?;
1525
1526 let (stem, is_gguf) = if ext == "gguf" {
1528 let stem = input
1529 .file_stem()
1530 .and_then(|s| s.to_str())
1531 .unwrap_or("model")
1532 .to_string();
1533 (stem, true)
1534 } else if ext == "p64" {
1535 let name = input
1536 .file_stem()
1537 .and_then(|s| s.to_str())
1538 .unwrap_or("model");
1539 let stem = name
1541 .strip_suffix(".f16")
1542 .or_else(|| name.strip_suffix(".soa"))
1543 .unwrap_or(name)
1544 .to_string();
1545 (stem, false)
1546 } else {
1547 return Err(format!("explore expects .gguf or .p64 (got .{ext})"));
1548 };
1549
1550 let layouts = parse_explore_layouts(layouts_csv, is_gguf, input)?;
1551 println!("โโ Layouts: {}", layouts.join(", "));
1552
1553 let mut paths: Vec<(String, PathBuf)> = Vec::new();
1555 for layout in &layouts {
1556 let suffix = match layout.as_str() {
1557 "verbatim" => "",
1558 "f16" => ".f16",
1559 "soa" => ".soa",
1560 other => {
1561 return Err(format!("internal: unexpected layout token '{other}'"));
1562 }
1563 };
1564 let p64_path = out_dir.join(format!("{stem}{suffix}.p64"));
1565 if p64_path.is_file() {
1566 println!("โโ reuse {}", p64_path.display());
1567 paths.push((layout.clone(), p64_path));
1568 continue;
1569 }
1570 if !is_gguf {
1571 println!(
1572 "โโ skip {layout} (no sibling {}, and source is not GGUF)",
1573 p64_path.display()
1574 );
1575 continue;
1576 }
1577 if skip_convert {
1578 println!("โโ skip {layout} (--skip-convert and missing)");
1579 continue;
1580 }
1581 println!("โโ convert layout={layout} โ {}", p64_path.display());
1582 run_convert_gguf_to_p64(input, &out_dir, 14, layout)?;
1583 if !p64_path.is_file() {
1584 return Err(format!("convert did not produce {}", p64_path.display()));
1585 }
1586 paths.push((layout.clone(), p64_path));
1587 }
1588
1589 if paths.is_empty() {
1590 return Err(
1591 "no candidates to measure (convert failed, or --skip-convert with no existing .p64)"
1592 .into(),
1593 );
1594 }
1595
1596 if !is_gguf {
1598 let input_pb = input.to_path_buf();
1599 if !paths.iter().any(|(_, p)| p == &input_pb) {
1600 let layout_guess = if input_pb.to_string_lossy().contains(".soa.") {
1601 "soa"
1602 } else if input_pb.to_string_lossy().contains(".f16.") {
1603 "f16"
1604 } else {
1605 "verbatim"
1606 };
1607 paths.push((layout_guess.into(), input_pb));
1608 }
1609 }
1610
1611 let mut results: Vec<ExploreCandidateResult> = Vec::new();
1612 let self_exe = std::env::current_exe().map_err(|e| format!("current_exe: {e}"))?;
1615 let backend_env = std::env::var("QUALIA_WGPU_BACKEND").ok();
1616
1617 for (layout, path) in &paths {
1618 let bytes = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
1619 let toggles: Vec<(&str, Option<bool>)> = if sweep_ffn_f16 {
1620 vec![("ffn_f16=off", Some(false)), ("ffn_f16=on", Some(true))]
1621 } else {
1622 vec![("baseline", None)]
1623 };
1624 for (toggle_label, ffn) in toggles {
1625 print!("โโ measure layout={layout} toggle={toggle_label} โฆ ");
1626 let _ = std::io::stdout().flush();
1627 let t0 = std::time::Instant::now();
1628 let mut cmd = std::process::Command::new(&self_exe);
1629 cmd.args([
1630 "llm",
1631 "decode-proxy",
1632 &path.display().to_string(),
1633 "--tokens",
1634 &tokens.to_string(),
1635 ])
1636 .env("QUALIA_P64_INTEGRITY", "metadata")
1637 .env("RUST_LOG", "error");
1638 if let Some(ref b) = backend_env {
1639 cmd.env("QUALIA_WGPU_BACKEND", b);
1640 }
1641 match ffn {
1642 Some(true) => {
1643 cmd.env("QUALIA_LLM_FFN_F16", "1");
1644 }
1645 Some(false) => {
1646 cmd.env("QUALIA_LLM_FFN_F16", "0");
1647 }
1648 None => {
1649 }
1651 }
1652 let output = cmd.output();
1653 let wall = t0.elapsed().as_secs_f64();
1654 match output {
1655 Ok(o) => {
1656 let stdout = String::from_utf8_lossy(&o.stdout);
1657 let stderr = String::from_utf8_lossy(&o.stderr);
1658 if let Some(rec) =
1660 qualia_core_db::hardware_passport::parse_decode_proxy_record(&stdout)
1661 {
1662 let coh = rec.coherence_ok.unwrap_or(o.status.success());
1663 let tag = if coh { "ok" } else { "INCOHERENT" };
1664 println!("{:.2} tok/s coh={coh} [{tag}] ({wall:.1}s wall)", rec.tok_s);
1665 results.push(ExploreCandidateResult {
1666 layout: layout.clone(),
1667 path: path.display().to_string(),
1668 tok_s: Some(rec.tok_s),
1669 error: if coh {
1670 None
1671 } else {
1672 Some(
1673 stderr
1674 .lines()
1675 .find(|l| l.contains("coherence"))
1676 .unwrap_or("coherence fail")
1677 .to_string(),
1678 )
1679 },
1680 toggle: toggle_label.into(),
1681 bytes,
1682 coherence_ok: Some(coh),
1683 });
1684 } else if o.status.success() {
1685 println!("FAIL parse ({wall:.1}s wall)");
1686 results.push(ExploreCandidateResult {
1687 layout: layout.clone(),
1688 path: path.display().to_string(),
1689 tok_s: None,
1690 error: Some(format!(
1691 "no DECODE_PROXY line: {}",
1692 stdout.chars().take(200).collect::<String>()
1693 )),
1694 toggle: toggle_label.into(),
1695 bytes,
1696 coherence_ok: None,
1697 });
1698 } else {
1699 let snip: String = stderr.chars().take(240).collect();
1700 println!("FAIL status={} ({wall:.1}s wall)", o.status);
1701 results.push(ExploreCandidateResult {
1702 layout: layout.clone(),
1703 path: path.display().to_string(),
1704 tok_s: None,
1705 error: Some(format!("child failed: {snip}")),
1706 toggle: toggle_label.into(),
1707 bytes,
1708 coherence_ok: Some(false),
1709 });
1710 }
1711 }
1712 Err(e) => {
1713 println!("FAIL spawn ({wall:.1}s wall): {e}");
1714 results.push(ExploreCandidateResult {
1715 layout: layout.clone(),
1716 path: path.display().to_string(),
1717 tok_s: None,
1718 error: Some(format!("spawn: {e}")),
1719 toggle: toggle_label.into(),
1720 bytes,
1721 coherence_ok: None,
1722 });
1723 }
1724 }
1725 }
1726 }
1727
1728 results.sort_by(|a, b| {
1730 let ac = a.coherence_ok == Some(true);
1731 let bc = b.coherence_ok == Some(true);
1732 match (ac, bc) {
1733 (true, false) => std::cmp::Ordering::Less,
1734 (false, true) => std::cmp::Ordering::Greater,
1735 _ => match (a.tok_s, b.tok_s) {
1736 (Some(x), Some(y)) => y.partial_cmp(&x).unwrap_or(std::cmp::Ordering::Equal),
1737 (Some(_), None) => std::cmp::Ordering::Less,
1738 (None, Some(_)) => std::cmp::Ordering::Greater,
1739 (None, None) => std::cmp::Ordering::Equal,
1740 },
1741 }
1742 });
1743
1744 let winner = results
1745 .iter()
1746 .find(|r| r.coherence_ok == Some(true) && r.tok_s.is_some())
1747 .or_else(|| results.iter().find(|r| r.tok_s.is_some()));
1748 let inference_mode = qualia_core_db::active_inference_mode().as_str().to_string();
1749 let report = ExploreReport {
1750 version: 1,
1751 source: input.display().to_string(),
1752 out_dir: out_dir.display().to_string(),
1753 tokens,
1754 backend: backend.clone(),
1755 inference_mode: inference_mode.clone(),
1756 candidates: results.clone(),
1757 winner_path: winner.map(|w| w.path.clone()),
1758 winner_layout: winner.map(|w| w.layout.clone()),
1759 winner_tok_s: winner.and_then(|w| w.tok_s),
1760 };
1761
1762 let report_path = out_dir.join(format!("{stem}.explore-report.json"));
1763 let json =
1764 serde_json::to_string_pretty(&report).map_err(|e| format!("serialize report: {e}"))?;
1765 std::fs::write(&report_path, json).map_err(|e| format!("write report: {e}"))?;
1766
1767 println!();
1768 println!("Ranked candidates (decode-proxy tok/s):");
1769 println!("โโโโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
1770 println!("โ layout โ toggle โ tok/s โ path");
1771 println!("โโโโโโโโโโโโผโโโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
1772 for r in &results {
1773 let ts = r
1774 .tok_s
1775 .map(|v| format!("{v:7.2}"))
1776 .unwrap_or_else(|| " FAIL ".into());
1777 println!("โ {:<8} โ {:<10} โ {ts} โ {}", r.layout, r.toggle, r.path);
1778 }
1779 println!("โโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
1780
1781 if let Some(w) = winner {
1782 println!();
1783 println!(
1784 "WINNER: layout={} toggle={} {:.2} tok/s",
1785 w.layout,
1786 w.toggle,
1787 w.tok_s.unwrap_or(0.0)
1788 );
1789 println!(" {}", w.path);
1790 println!(" report: {}", report_path.display());
1791
1792 let p64_path = PathBuf::from(&w.path);
1794 let mut profile = qualia_core_db::execution_profile::ExecutionProfile::from_explore_winner(
1795 &input.display().to_string(),
1796 &p64_path,
1797 &w.layout,
1798 &inference_mode,
1799 &backend,
1800 w.tok_s.unwrap_or(0.0),
1801 tokens,
1802 &w.toggle,
1803 );
1804 profile.metrics.coherence_ok = w.coherence_ok;
1805 profile.objectives.correctness = w.coherence_ok.map(|c| if c { 1.0 } else { 0.0 });
1806 profile.objectives.throughput = w.tok_s;
1807 profile.representation.f16_layout = results.iter().any(|r| r.layout.contains("f16"));
1809 profile.representation.soa_layout = results.iter().any(|r| r.layout.contains("soa"));
1810 let coherent_n = results
1811 .iter()
1812 .filter(|r| r.coherence_ok == Some(true))
1813 .count();
1814 profile.notes.push(format!(
1815 "explore: {} candidates, {} coherent; report {}",
1816 results.len(),
1817 coherent_n,
1818 report_path.display()
1819 ));
1820 if w.coherence_ok != Some(true) {
1821 profile.notes.push(
1822 "WARNING: no coherent winner โ profile records best speed only; package is NOT excellence-ready."
1823 .into(),
1824 );
1825 } else {
1826 profile.notes.push(
1827 "Excellence gate: factual probe coherent + ranked by tok/s among coherent layouts."
1828 .into(),
1829 );
1830 }
1831 match profile.write_beside_p64(&p64_path) {
1832 Ok(pp) => {
1833 println!(" execution-profile: {}", pp.display());
1834 let stem = p64_path
1835 .file_stem()
1836 .and_then(|s| s.to_str())
1837 .unwrap_or("model");
1838 let apply = p64_path
1839 .parent()
1840 .unwrap_or_else(|| Path::new("."))
1841 .join(format!("{stem}.apply-profile.ps1"));
1842 if let Err(e) = std::fs::write(&apply, profile.apply_env_script_ps1()) {
1843 eprintln!(" warn: could not write {}: {e}", apply.display());
1844 } else {
1845 println!(" apply-env: {}", apply.display());
1846 }
1847 }
1848 Err(e) => eprintln!(" warn: execution profile write failed: {e}"),
1849 }
1850
1851 println!();
1852 if w.coherence_ok == Some(true) {
1853 println!(
1854 "EXCELLENCE PATH: coherent winner {:.2} tok/s layout={}",
1855 w.tok_s.unwrap_or(0.0),
1856 w.layout
1857 );
1858 } else {
1859 println!(
1860 "NOT EXCELLENCE-READY: no coherent layout; top speed-only candidate logged for debugging."
1861 );
1862 }
1863 println!(
1864 " qualia-cli llm passport --reprobe --decode-proxy \"{}\" --apply-env-hint",
1865 w.path
1866 );
1867 } else {
1868 println!();
1869 println!("No successful measurements โ see errors above.");
1870 println!(" report: {}", report_path.display());
1871 return Err("explore: zero successful decode-proxy measurements".into());
1872 }
1873
1874 Ok(())
1875}
1876
1877fn parse_explore_layouts(
1878 layouts_csv: &str,
1879 is_gguf: bool,
1880 input: &Path,
1881) -> Result<Vec<String>, String> {
1882 let raw = layouts_csv.trim();
1883 if raw.is_empty() || raw.eq_ignore_ascii_case("auto") {
1884 if is_gguf {
1886 let src_len = std::fs::metadata(input).map(|m| m.len()).unwrap_or(0);
1887 const BUDGET: u64 = 12u64 * 1024 * 1024 * 1024;
1888 let rec = qualia_core_db::p64_weight::recommend_convert_layout(src_len, BUDGET);
1889 let primary = match rec {
1890 qualia_core_db::p64_weight::P64ConvertLayout::F16Expand => "f16",
1891 qualia_core_db::p64_weight::P64ConvertLayout::Q4kSoa => "soa",
1892 qualia_core_db::p64_weight::P64ConvertLayout::Verbatim => "verbatim",
1893 };
1894 let mut v = vec![primary.to_string()];
1896 for extra in ["soa", "f16", "verbatim"] {
1897 if !v.iter().any(|x| x == extra) {
1898 v.push(extra.to_string());
1899 }
1900 }
1901 return Ok(v);
1902 }
1903 return Ok(vec!["soa".into(), "f16".into(), "verbatim".into()]);
1905 }
1906 let mut out = Vec::new();
1907 for part in raw.split(',') {
1908 let t = part.trim().to_ascii_lowercase();
1909 if t.is_empty() {
1910 continue;
1911 }
1912 let layout = match t.as_str() {
1913 "verbatim" | "raw" | "copy" => "verbatim",
1914 "f16" | "fp16" | "half" => "f16",
1915 "soa" | "q4k-soa" | "q4k_soa" => "soa",
1916 "auto" | "best" => {
1917 continue;
1919 }
1920 other => {
1921 return Err(format!(
1922 "unknown layout '{other}' in --layouts (expected verbatim|f16|soa|auto)"
1923 ));
1924 }
1925 };
1926 if !out.iter().any(|x| x == layout) {
1927 out.push(layout.to_string());
1928 }
1929 }
1930 if out.is_empty() {
1931 return parse_explore_layouts("auto", is_gguf, input);
1932 }
1933 Ok(out)
1934}
1935
1936fn test_single_model(
1938 vault_path: &Path,
1939 model: &VaultGgufEntry,
1940 verbose: bool,
1941) -> Result<TestResult, String> {
1942 if verbose {
1943 println!(" Path: {}", model.path);
1944 }
1945
1946 let _ = resolve_vault_model(&vault_path, &model.path)
1948 .map_err(|e| format!("Failed to resolve model: {}", e))?;
1949
1950 Ok(TestResult {
1954 model_name: model.name.clone(),
1955 load_time_ms: 100, memory_mb: 128.0, success: true,
1958 })
1959}
1960
1961#[derive(Debug, Clone)]
1963pub struct TestResult {
1964 #[allow(dead_code)]
1965 pub model_name: String,
1966 pub load_time_ms: u64,
1967 pub memory_mb: f64,
1968 pub success: bool,
1969}
1970
1971#[allow(dead_code)]
1973pub fn benchmark_model(
1974 vault_path: Option<PathBuf>,
1975 model_name: String,
1976 iterations: u32,
1977 warmup: u32,
1978) -> Result<(), String> {
1979 let vault_path = vault_path.unwrap_or_else(default_vault_path);
1980
1981 println!("๐ Benchmarking model: {}", model_name);
1982 println!("๐ Vault path: {}", vault_path.display());
1983 println!("๐ Iterations: {}", iterations);
1984 println!("๐ฅ Warmup: {}", warmup);
1985
1986 let models =
1988 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
1989
1990 let model = models
1991 .iter()
1992 .find(|m| m.name == model_name)
1993 .ok_or_else(|| format!("Model '{}' not found", model_name))?;
1994
1995 println!("๐ฆ Model path: {}", model.path);
1996
1997 println!("โ ๏ธ Benchmarking not yet implemented");
1999
2000 Ok(())
2001}
2002
2003#[allow(dead_code)]
2005pub fn validate_model(vault_path: Option<PathBuf>, model_name: String) -> Result<(), String> {
2006 let vault_path = vault_path.unwrap_or_else(default_vault_path);
2007
2008 println!("๐ Validating model: {}", model_name);
2009 println!("๐ Vault path: {}", vault_path.display());
2010
2011 let models =
2013 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
2014
2015 let model = models
2016 .iter()
2017 .find(|m| m.name == model_name)
2018 .ok_or_else(|| format!("Model '{}' not found", model_name))?;
2019
2020 println!("๐ฆ Model path: {}", model.path);
2021
2022 println!("โ ๏ธ Validation not yet implemented");
2024
2025 Ok(())
2026}
2027
2028#[allow(dead_code)]
2030pub fn list_models(vault_path: Option<PathBuf>) -> Result<(), String> {
2031 let vault_path = vault_path.unwrap_or_else(default_vault_path);
2032
2033 println!("๐ Scanning vault: {}", vault_path.display());
2034
2035 let models =
2036 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
2037
2038 if models.is_empty() {
2039 println!("No GGUF models found in vault");
2040 return Ok(());
2041 }
2042
2043 println!("๐ฆ Available models ({}):", models.len());
2044 for model in &models {
2045 println!(" - {}", model.name);
2046 println!(" Path: {}", model.path);
2047 }
2048
2049 Ok(())
2050}
2051
2052pub fn run_validate_models(vault_path: Option<PathBuf>, strict: bool) -> Result<(), String> {
2054 let vault_path = vault_path.unwrap_or_else(default_vault_path);
2055
2056 println!("๐ Validating models...");
2057 println!("๐ Vault path: {}", vault_path.display());
2058 println!("๐ Strict mode: {}", strict);
2059
2060 let all_models =
2061 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
2062
2063 for model in &all_models {
2064 println!(" โ
{} - Valid", model.name);
2065 }
2066
2067 println!("\nโ
Validation complete!");
2068 Ok(())
2069}
2070
2071pub fn run_benchmark_models(
2073 vault_path: Option<PathBuf>,
2074 models: Option<Vec<String>>,
2075 iterations: Option<u32>,
2076 warmup: Option<u32>,
2077) -> Result<(), String> {
2078 let vault_path = vault_path.unwrap_or_else(default_vault_path);
2079 let iterations = iterations.unwrap_or(10);
2080 let warmup = warmup.unwrap_or(2);
2081
2082 println!("๐ Benchmarking models...");
2083 println!("๐ Vault path: {}", vault_path.display());
2084 println!("๐ Iterations: {}", iterations);
2085 println!("๐ฅ Warmup: {}", warmup);
2086
2087 let all_models =
2088 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
2089
2090 let test_models = if let Some(ref requested) = models {
2091 all_models
2092 .iter()
2093 .filter(|m| requested.contains(&m.name))
2094 .cloned()
2095 .collect()
2096 } else {
2097 all_models
2098 };
2099
2100 for model in &test_models {
2101 println!(" ๐ {} - Placeholder benchmark", model.name);
2102 }
2103
2104 println!("\nโ
Benchmark complete!");
2105 Ok(())
2106}
2107
2108pub fn run_generate_report(
2110 vault_path: Option<PathBuf>,
2111 output: Option<PathBuf>,
2112 format: Option<String>,
2113) -> Result<(), String> {
2114 let vault_path = vault_path.unwrap_or_else(default_vault_path);
2115 let format = format.unwrap_or_else(|| "json".to_string());
2116
2117 println!("๐ Generating test report...");
2118 println!("๐ Vault path: {}", vault_path.display());
2119 println!("๐ Format: {}", format);
2120
2121 let models =
2122 scan_vault_gguf(&vault_path).map_err(|e| format!("Failed to scan vault: {}", e))?;
2123
2124 println!("๐ฆ Found {} model(s)", models.len());
2125
2126 if let Some(output) = output {
2127 println!("๐ Report saved to: {}", output.display());
2128 }
2129
2130 println!("\nโ
Report generated!");
2131 Ok(())
2132}