aprender-serve 0.64.0

Pure Rust ML inference engine built from scratch - model serving for GGUF and safetensors

/// Test PARITY-011d: QA-044 bench-wgpu gracefully skips if unavailable
///
/// Verifies graceful degradation when GPU/WGPU is not available.
#[test]
fn test_parity011d_wgpu_graceful_skip() {
    /// GPU availability status
    #[derive(Debug, Clone)]
    enum GpuStatus {
        Available { device: String, memory_mb: u64 },
        NotCompiled,
        NoDevice,
        DriverError(String),
    }

    impl GpuStatus {
        fn should_skip(&self) -> bool {
            !matches!(self, GpuStatus::Available { .. })
        }

        fn skip_reason(&self) -> Option<String> {
            match self {
                GpuStatus::Available { .. } => None,
                GpuStatus::NotCompiled => Some("GPU feature not compiled".to_string()),
                GpuStatus::NoDevice => Some("No GPU device found".to_string()),
                GpuStatus::DriverError(e) => Some(format!("Driver error: {}", e)),
            }
        }
    }

    /// WGPU benchmark with graceful skip
    struct WgpuBenchmark {
        gpu_status: GpuStatus,
    }

    impl WgpuBenchmark {
        fn run(&self) -> std::result::Result<f64, String> {
            match &self.gpu_status {
                GpuStatus::Available { .. } => Ok(1000.0), // 1000 tok/s on GPU
                _ => Err(self.gpu_status.skip_reason().expect("test")),
            }
        }

        fn run_with_fallback(&self, cpu_throughput: f64) -> (f64, String) {
            match self.run() {
                Ok(tps) => (tps, "GPU".to_string()),
                Err(reason) => {
                    println!("  ⚠️ GPU skipped: {}", reason);
                    (cpu_throughput, "CPU (fallback)".to_string())
                },
            }
        }
    }

    // Test: GPU available
    let bench = WgpuBenchmark {
        gpu_status: GpuStatus::Available {
            device: "NVIDIA RTX 3080".to_string(),
            memory_mb: 10240,
        },
    };
    let (tps, backend) = bench.run_with_fallback(100.0);
    assert_eq!(backend, "GPU", "QA-044: Uses GPU when available");
    assert!(tps > 500.0, "QA-044: GPU throughput high");

    // Test: GPU not compiled
    let bench = WgpuBenchmark {
        gpu_status: GpuStatus::NotCompiled,
    };
    let (_tps, backend) = bench.run_with_fallback(100.0);
    assert_eq!(backend, "CPU (fallback)", "QA-044: Falls back to CPU");
    assert!(
        bench.gpu_status.should_skip(),
        "QA-044: Correctly identifies skip"
    );

    // Test: No device
    let bench = WgpuBenchmark {
        gpu_status: GpuStatus::NoDevice,
    };
    assert!(bench.gpu_status.should_skip(), "QA-044: No device = skip");
    assert!(
        bench
            .gpu_status
            .skip_reason()
            .expect("test")
            .contains("No GPU"),
        "QA-044: Clear skip reason"
    );

    // Test: Driver error
    let bench = WgpuBenchmark {
        gpu_status: GpuStatus::DriverError("Vulkan 1.3 required".to_string()),
    };
    assert!(
        bench
            .gpu_status
            .skip_reason()
            .expect("test")
            .contains("Vulkan"),
        "QA-044: Driver error in reason"
    );

    println!("\nPARITY-011d: WGPU graceful skip");
    println!(
        "  NotCompiled skip: {}",
        GpuStatus::NotCompiled.should_skip()
    );
    println!("  NoDevice skip: {}", GpuStatus::NoDevice.should_skip());
}

/// Test PARITY-011e: QA-045 bench-gguf-gpu-inference compares all runtimes
///
/// Verifies GGUF GPU inference comparison across realizar/ollama/llama.cpp.
#[test]
fn test_parity011e_gguf_gpu_matrix() {
    /// GGUF runtime for benchmarking
    #[derive(Debug, Clone)]
    struct GgufRuntime {
        name: String,
        version: String,
        gpu_backend: String,
    }

    /// GGUF benchmark result
    #[derive(Debug)]
    struct GgufBenchResult {
        runtime: String,
        throughput_tps: f64,
        ttft_ms: f64,
        memory_mb: u64,
    }

    /// GGUF GPU comparison matrix
    struct GgufGpuMatrix {
        runtimes: Vec<GgufRuntime>,
    }

    impl GgufGpuMatrix {
        fn standard() -> Self {
            Self {
                runtimes: vec![
                    GgufRuntime {
                        name: "Realizar".to_string(),
                        version: "0.2.3".to_string(),
                        gpu_backend: "wgpu".to_string(),
                    },
                    GgufRuntime {
                        name: "Ollama".to_string(),
                        version: "0.3.x".to_string(),
                        gpu_backend: "CUDA/Metal".to_string(),
                    },
                    GgufRuntime {
                        name: "llama.cpp".to_string(),
                        version: "b2xxx".to_string(),
                        gpu_backend: "CUDA/Metal/Vulkan".to_string(),
                    },
                ],
            }
        }

        fn benchmark(&self, _model: &str) -> Vec<GgufBenchResult> {
            // test benchmark results
            vec![
                GgufBenchResult {
                    runtime: "Realizar".to_string(),
                    throughput_tps: 0.17, // Current state
                    ttft_ms: 500.0,
                    memory_mb: 2048,
                },
                GgufBenchResult {
                    runtime: "Ollama".to_string(),
                    throughput_tps: 225.0,
                    ttft_ms: 45.0,
                    memory_mb: 3072,
                },
                GgufBenchResult {
                    runtime: "llama.cpp".to_string(),
                    throughput_tps: 280.0,
                    ttft_ms: 35.0,
                    memory_mb: 2560,
                },
            ]
        }

        fn compute_gaps(&self, results: &[GgufBenchResult]) -> Vec<(String, f64)> {
            let baseline = results
                .iter()
                .find(|r| r.runtime == "Ollama")
                .map_or(1.0, |r| r.throughput_tps);

            results
                .iter()
                .map(|r| (r.runtime.clone(), baseline / r.throughput_tps))
                .collect()
        }
    }

    let matrix = GgufGpuMatrix::standard();
    assert_eq!(matrix.runtimes.len(), 3, "QA-045: Three runtimes compared");

    let results = matrix.benchmark("phi-2-q4_k_m.gguf");
    assert_eq!(results.len(), 3, "QA-045: Results for all runtimes");

    let gaps = matrix.compute_gaps(&results);
    let realizar_gap = gaps
        .iter()
        .find(|(n, _)| n == "Realizar")
        .map(|(_, g)| *g)
        .expect("test");
    assert!(
        realizar_gap > 1000.0,
        "QA-045: Gap correctly computed (>1000x)"
    );

    println!("\nPARITY-011e: GGUF GPU inference matrix");
    for result in &results {
        println!(
            "  {}: {:.2} tok/s, TTFT={:.0}ms",
            result.runtime, result.throughput_tps, result.ttft_ms
        );
    }
    println!("  Realizar gap: {:.0}x", realizar_gap);
}

/// Test PARITY-011f: QA-046 bench-apr-gpu-inference format comparison
///
/// Verifies APR vs GGUF format comparison for GPU inference.
#[test]
fn test_parity011f_apr_gguf_format_comparison() {
    /// Model format for benchmarking
    #[derive(Debug, Clone)]
    enum ModelFormat {
        Apr { version: String },
        Gguf { quant: String },
    }

    impl ModelFormat {
        fn name(&self) -> &str {
            match self {
                ModelFormat::Apr { .. } => "APR",
                ModelFormat::Gguf { .. } => "GGUF",
            }
        }

        fn size_ratio(&self) -> f64 {
            match self {
                ModelFormat::Apr { .. } => 1.0, // F32 baseline
                ModelFormat::Gguf { quant } => match quant.as_str() {
                    "Q4_K_M" => 0.25, // ~4-bit
                    "Q8_0" => 0.5,    // ~8-bit
                    _ => 0.5,
                },
            }
        }
    }

    /// Format comparison result
    #[derive(Debug)]
    struct FormatComparison {
        format: String,
        throughput_tps: f64,
        model_size_mb: f64,
        load_time_ms: f64,
    }

    /// Format comparison benchmark
    struct FormatBenchmark {
        base_size_mb: f64,
        formats: Vec<ModelFormat>,
    }

    impl FormatBenchmark {
        fn run(&self) -> Vec<FormatComparison> {
            self.formats
                .iter()
                .map(|f| {
                    let size = self.base_size_mb * f.size_ratio();
                    // Smaller models load faster and have better memory bandwidth
                    let load_time = size * 0.5; // 0.5ms per MB
                    let throughput = match f {
                        ModelFormat::Apr { .. } => 50.0,   // F32 slower
                        ModelFormat::Gguf { .. } => 225.0, // Quantized faster
                    };
                    FormatComparison {
                        format: f.name().to_string(),
                        throughput_tps: throughput,
                        model_size_mb: size,
                        load_time_ms: load_time,
                    }
                })
                .collect()
        }
    }

    let bench = FormatBenchmark {
        base_size_mb: 2000.0, // 2GB F32 model
        formats: vec![
            ModelFormat::Apr {
                version: "1.0".to_string(),
            },
            ModelFormat::Gguf {
                quant: "Q4_K_M".to_string(),
            },
        ],
    };

    let results = bench.run();
    assert_eq!(results.len(), 2, "QA-046: Two formats compared");

    let apr = results.iter().find(|r| r.format == "APR").expect("test");
    let gguf = results.iter().find(|r| r.format == "GGUF").expect("test");

    // GGUF should be smaller (quantized)
    assert!(
        gguf.model_size_mb < apr.model_size_mb,
        "QA-046: GGUF smaller than APR"
    );
    // GGUF should be faster (better memory bandwidth)
    assert!(
        gguf.throughput_tps > apr.throughput_tps,
        "QA-046: GGUF faster than APR"
    );

    println!("\nPARITY-011f: APR vs GGUF format comparison");
    for r in &results {
        println!(
            "  {}: {:.0} tok/s, {:.0} MB, load={:.0}ms",
            r.format, r.throughput_tps, r.model_size_mb, r.load_time_ms
        );
    }
}