Skip to main content
Glama

CodeGraph CLI MCP Server

by Jakedismo
gpu.rs11.9 kB
use codegraph_core::{CodeGraphError, Result}; use serde::{Deserialize, Serialize}; use std::time::Instant; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GpuDeviceInfo { pub available: bool, pub device_name: String, pub memory_gb: f64, pub compute_major: u32, pub compute_minor: u32, pub max_threads_per_block: u32, pub multiprocessor_count: u32, } #[derive(Debug)] pub struct GpuMemoryAllocation { device_ptr: usize, size_bytes: usize, is_valid: bool, } impl GpuMemoryAllocation { pub fn new(size_bytes: usize) -> Self { Self { device_ptr: 0x1000000, // Mock pointer for testing size_bytes, is_valid: true, } } pub fn is_valid(&self) -> bool { self.is_valid } pub fn size(&self) -> usize { self.size_bytes } pub fn invalidate(&mut self) { self.is_valid = false; } } #[derive(Debug)] pub struct GpuVectorData { allocation: GpuMemoryAllocation, vector_count: usize, dimension: usize, uploaded: bool, } impl GpuVectorData { pub fn new(allocation: GpuMemoryAllocation, vector_count: usize, dimension: usize) -> Self { Self { allocation, vector_count, dimension, uploaded: false, } } pub fn is_uploaded(&self) -> bool { self.uploaded } pub fn mark_uploaded(&mut self) { self.uploaded = true; } pub fn vector_count(&self) -> usize { self.vector_count } pub fn dimension(&self) -> usize { self.dimension } } #[derive(Debug)] pub struct CpuFallback { available: bool, thread_count: usize, } impl CpuFallback { pub fn new() -> Self { Self { available: true, thread_count: num_cpus::get(), } } pub fn is_available(&self) -> bool { self.available } pub fn thread_count(&self) -> usize { self.thread_count } } pub struct GpuAcceleration { device_info: GpuDeviceInfo, allocations: Vec<GpuMemoryAllocation>, cpu_fallback: CpuFallback, } impl GpuAcceleration { pub fn new() -> Result<Self> { // In a real implementation, this would detect actual GPU hardware // For now, we'll simulate GPU detection let device_info = Self::detect_gpu_device()?; Ok(Self { device_info, allocations: Vec::new(), cpu_fallback: CpuFallback::new(), }) } fn detect_gpu_device() -> Result<GpuDeviceInfo> { // Simulate GPU detection - in real implementation would use CUDA/OpenCL/Metal #[cfg(target_os = "macos")] let gpu_available = Self::detect_metal_gpu(); #[cfg(not(target_os = "macos"))] let gpu_available = Self::detect_cuda_gpu(); if gpu_available { Ok(GpuDeviceInfo { available: true, device_name: "Apple M-Series GPU".to_string(), // Or detected GPU name memory_gb: 16.0, // Unified memory on Apple Silicon compute_major: 2, compute_minor: 0, max_threads_per_block: 1024, multiprocessor_count: 10, }) } else { Ok(GpuDeviceInfo { available: false, device_name: "No GPU detected".to_string(), memory_gb: 0.0, compute_major: 0, compute_minor: 0, max_threads_per_block: 0, multiprocessor_count: 0, }) } } #[cfg(target_os = "macos")] fn detect_metal_gpu() -> bool { // In real implementation, would use Metal framework to detect GPU // For now, assume GPU is available on macOS true } #[cfg(not(target_os = "macos"))] fn detect_cuda_gpu() -> bool { // In real implementation, would check for CUDA runtime // For now, simulate based on common GPU presence std::env::var("CUDA_VISIBLE_DEVICES").is_ok() || std::path::Path::new("/usr/local/cuda").exists() } pub fn get_device_info(&self) -> Result<&GpuDeviceInfo> { Ok(&self.device_info) } pub fn allocate_memory(&mut self, size_bytes: usize) -> Result<GpuMemoryAllocation> { if !self.device_info.available { return Err(CodeGraphError::Vector("GPU not available".to_string())); } if size_bytes == 0 { return Err(CodeGraphError::Vector( "Cannot allocate zero bytes".to_string(), )); } // Check if we have enough memory (simplified check) let total_allocated: usize = self.allocations.iter().map(|a| a.size()).sum(); let available_memory = (self.device_info.memory_gb * 1024.0 * 1024.0 * 1024.0) as usize; if total_allocated + size_bytes > available_memory { return Err(CodeGraphError::Vector( "Insufficient GPU memory".to_string(), )); } let allocation = GpuMemoryAllocation::new(size_bytes); self.allocations.push(allocation); // Return a copy of the allocation Ok(GpuMemoryAllocation::new(size_bytes)) } pub fn deallocate_memory(&mut self, mut allocation: GpuMemoryAllocation) -> Result<()> { if !self.device_info.available { return Err(CodeGraphError::Vector("GPU not available".to_string())); } allocation.invalidate(); // In real implementation, would call cudaFree or equivalent // For now, just simulate deallocation self.allocations .retain(|a| a.device_ptr != allocation.device_ptr); Ok(()) } pub fn upload_vectors(&self, vectors: &[f32], dimension: usize) -> Result<GpuVectorData> { if !self.device_info.available { return Err(CodeGraphError::Vector("GPU not available".to_string())); } if vectors.len() % dimension != 0 { return Err(CodeGraphError::Vector( "Vector data length not divisible by dimension".to_string(), )); } let vector_count = vectors.len() / dimension; let size_bytes = vectors.len() * std::mem::size_of::<f32>(); // Simulate GPU memory allocation and upload let allocation = GpuMemoryAllocation::new(size_bytes); let mut gpu_data = GpuVectorData::new(allocation, vector_count, dimension); // Simulate upload time based on data size let upload_time_ms = (size_bytes / 1024 / 1024) as u64; // 1ms per MB std::thread::sleep(std::time::Duration::from_millis(upload_time_ms.min(10))); gpu_data.mark_uploaded(); Ok(gpu_data) } pub fn compute_distances( &self, query: &[f32], gpu_data: &GpuVectorData, limit: usize, ) -> Result<Vec<f32>> { if !self.device_info.available { return Err(CodeGraphError::Vector("GPU not available".to_string())); } if !gpu_data.is_uploaded() { return Err(CodeGraphError::Vector( "Vector data not uploaded to GPU".to_string(), )); } if query.len() != gpu_data.dimension() { return Err(CodeGraphError::Vector(format!( "Query dimension {} doesn't match GPU data dimension {}", query.len(), gpu_data.dimension() ))); } // Simulate GPU-accelerated distance computation let start = Instant::now(); // In real implementation, this would launch GPU kernels let mut distances = Vec::new(); for i in 0..limit.min(gpu_data.vector_count()) { // Simulate distance computation with some variability let distance = (i as f32 * 0.1) + (query[0] * 0.01); distances.push(distance); } let computation_time = start.elapsed(); // Simulate realistic GPU computation time if computation_time < std::time::Duration::from_micros(100) { std::thread::sleep(std::time::Duration::from_micros(100)); } Ok(distances) } pub fn get_cpu_fallback(&self) -> Result<&CpuFallback> { Ok(&self.cpu_fallback) } pub fn compute_distances_cpu( &self, query: &[f32], vectors: &[f32], dimension: usize, limit: usize, ) -> Result<Vec<f32>> { if vectors.len() % dimension != 0 { return Err(CodeGraphError::Vector( "Invalid vector data layout".to_string(), )); } let vector_count = vectors.len() / dimension; let mut distances = Vec::new(); for i in 0..limit.min(vector_count) { let start_idx = i * dimension; let vector = &vectors[start_idx..start_idx + dimension]; let distance = self.cosine_distance(query, vector); distances.push(distance); } Ok(distances) } fn cosine_distance(&self, a: &[f32], b: &[f32]) -> f32 { if a.len() != b.len() { return f32::INFINITY; } let dot_product: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum(); let norm_a: f32 = a.iter().map(|x| x * x).sum::<f32>().sqrt(); let norm_b: f32 = b.iter().map(|x| x * x).sum::<f32>().sqrt(); if norm_a == 0.0 || norm_b == 0.0 { return f32::INFINITY; } 1.0 - (dot_product / (norm_a * norm_b)) } pub fn get_memory_stats(&self) -> GpuMemoryStats { let total_allocated: usize = self.allocations.iter().map(|a| a.size()).sum(); let total_memory = (self.device_info.memory_gb * 1024.0 * 1024.0 * 1024.0) as usize; GpuMemoryStats { total_memory_bytes: total_memory, allocated_bytes: total_allocated, free_bytes: total_memory - total_allocated, allocation_count: self.allocations.len(), fragmentation_ratio: 0.0, // Simplified - real implementation would calculate fragmentation } } pub fn synchronize(&self) -> Result<()> { if !self.device_info.available { return Err(CodeGraphError::Vector("GPU not available".to_string())); } // In real implementation, would call cudaDeviceSynchronize or equivalent // For now, just simulate synchronization delay std::thread::sleep(std::time::Duration::from_micros(10)); Ok(()) } pub fn set_device(&mut self, device_id: u32) -> Result<()> { if !self.device_info.available { return Err(CodeGraphError::Vector("GPU not available".to_string())); } // In real implementation, would call cudaSetDevice or equivalent // For now, just validate device_id if device_id > 0 { return Err(CodeGraphError::Vector(format!( "Invalid device ID: {}", device_id ))); } Ok(()) } } #[derive(Debug, Clone)] pub struct GpuMemoryStats { pub total_memory_bytes: usize, pub allocated_bytes: usize, pub free_bytes: usize, pub allocation_count: usize, pub fragmentation_ratio: f32, } impl Default for GpuAcceleration { fn default() -> Self { Self::new().unwrap_or_else(|_| Self { device_info: GpuDeviceInfo { available: false, device_name: "Failed to initialize".to_string(), memory_gb: 0.0, compute_major: 0, compute_minor: 0, max_threads_per_block: 0, multiprocessor_count: 0, }, allocations: Vec::new(), cpu_fallback: CpuFallback::new(), }) } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jakedismo/codegraph-rust'

If you have feedback or need assistance with the MCP directory API, please join our Discord server