Skip to main content
Glama
performance.rs8.07 kB
use roberto_mcp::models::{Language, Location, Symbol, SymbolId, SymbolType, Visibility}; use roberto_mcp::{SymbolIndexer, SymbolStore}; use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use std::path::PathBuf; use std::sync::Arc; use std::time::Instant; fn create_test_symbol(name: &str, file: &str, line: u32) -> Symbol { let path = PathBuf::from(file); let location = Location::new(path.clone(), line, 0, line, 10); let symbol_id = SymbolId::new(&path, line, 0); Symbol { id: symbol_id, name: name.to_string(), symbol_type: SymbolType::Function, location, namespace: None, visibility: Visibility::Public, source: None, } } fn bench_symbol_lookup(c: &mut Criterion) { let store = Arc::new(SymbolStore::new()); // Insert 10,000 symbols for i in 0..10_000 { let symbol = create_test_symbol(&format!("function_{}", i), "test.rs", i + 1); store.insert_symbol_unchecked(symbol); } // Benchmark O(1) symbol lookup c.bench_function("symbol_lookup_o1", |b| { b.iter(|| { let symbols = store.get_symbols(black_box("function_5000")); black_box(symbols); }) }); // Target: <1ms lookups let mut group = c.benchmark_group("symbol_lookup_performance"); group.significance_level(0.1).sample_size(1000); for size in [100, 1_000, 10_000, 50_000].iter() { group.bench_with_input(BenchmarkId::new("lookup_time", size), size, |b, &size| { let store = Arc::new(SymbolStore::new()); // Insert symbols for i in 0..*size { let symbol = create_test_symbol(&format!("func_{}", i), "test.rs", i + 1); store.insert_symbol_unchecked(symbol); } b.iter(|| { let target = format!("func_{}", size / 2); let symbols = store.get_symbols(black_box(&target)); black_box(symbols); }); }); } group.finish(); } fn bench_symbol_insertion(c: &mut Criterion) { let mut group = c.benchmark_group("symbol_insertion"); group.significance_level(0.1).sample_size(100); for size in [100, 1_000, 5_000].iter() { group.bench_with_input(BenchmarkId::new("batch_insert", size), size, |b, &size| { b.iter_with_setup( || { let store = Arc::new(SymbolStore::new()); let mut symbols = Vec::new(); for i in 0..*size { symbols.push(create_test_symbol(&format!("func_{}", i), "test.rs", i + 1)); } (store, symbols) }, |(store, symbols)| { for symbol in symbols { store.insert_symbol_unchecked(black_box(symbol)); } }, ); }); } group.finish(); } fn bench_prefix_search(c: &mut Criterion) { let store = Arc::new(SymbolStore::new()); // Insert symbols with different prefixes for i in 0..1_000 { let symbol = create_test_symbol(&format!("test_function_{}", i), "test.rs", i + 1); store.insert_symbol_unchecked(symbol); } for i in 0..1_000 { let symbol = create_test_symbol(&format!("other_function_{}", i), "test.rs", i + 1001); store.insert_symbol_unchecked(symbol); } for i in 0..1_000 { let symbol = create_test_symbol(&format!("helper_function_{}", i), "test.rs", i + 2001); store.insert_symbol_unchecked(symbol); } c.bench_function("prefix_search", |b| { b.iter(|| { let results = store.find_symbols_by_prefix(black_box("test_")); black_box(results); }) }); } fn bench_file_indexing_simulation(c: &mut Criterion) { let mut group = c.benchmark_group("file_indexing_simulation"); group.significance_level(0.1).sample_size(50); // Simulate indexing different numbers of files for file_count in [10, 50, 100].iter() { group.bench_with_input( BenchmarkId::new("files", file_count), file_count, |b, &file_count| { b.iter_with_setup( || { let mut indexer = SymbolIndexer::new().unwrap(); let rust_code = r#" pub fn hello_world() { println!("Hello, world!"); } pub struct TestStruct { pub field: i32, } impl TestStruct { pub fn new(field: i32) -> Self { Self { field } } } "#; (indexer, rust_code) }, |(mut indexer, rust_code)| { let start = Instant::now(); for i in 0..*file_count { let file_path = PathBuf::from(format!("test_{}.rs", i)); let _symbols = indexer .extract_symbols( black_box(rust_code), Language::Rust, black_box(&file_path), ) .unwrap(); } let duration = start.elapsed(); // Target: >100 files/sec let files_per_second = (*file_count as f64) / duration.as_secs_f64(); // This is measured but not asserted in the benchmark black_box(files_per_second); }, ); }, ); } group.finish(); } fn bench_memory_usage(c: &mut Criterion) { let mut group = c.benchmark_group("memory_tracking"); group.bench_function("memory_tracking_overhead", |b| { b.iter_with_setup( || { let store = Arc::new(SymbolStore::new()); let symbol = create_test_symbol("test_function", "test.rs", 1); (store, symbol) }, |(store, symbol)| { let initial_memory = store.get_memory_usage(); store.insert_symbol_unchecked(black_box(symbol)); let final_memory = store.get_memory_usage(); black_box(final_memory - initial_memory); }, ); }); group.finish(); } fn bench_concurrent_access(c: &mut Criterion) { use std::sync::Arc; use std::thread; let store = Arc::new(SymbolStore::new()); // Pre-populate with symbols for i in 0..1_000 { let symbol = create_test_symbol(&format!("concurrent_func_{}", i), "test.rs", i + 1); store.insert_symbol_unchecked(symbol); } c.bench_function("concurrent_reads", |b| { b.iter(|| { let store_clone = Arc::clone(&store); let handles: Vec<_> = (0..4) .map(|thread_id| { let store = Arc::clone(&store_clone); thread::spawn(move || { for i in 0..100 { let target = format!("concurrent_func_{}", (thread_id * 100 + i) % 1000); let _symbols = store.get_symbols(&target); } }) }) .collect(); for handle in handles { handle.join().unwrap(); } }) }); } criterion_group!( benches, bench_symbol_lookup, bench_symbol_insertion, bench_prefix_search, bench_file_indexing_simulation, bench_memory_usage, bench_concurrent_access ); criterion_main!(benches);

Latest Blog Posts

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/kensave/CodeCortX-MCP'

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