Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
//! Attention engine benchmarks for RuvLLM
//!
//! Benchmarks multi-head graph attention.
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::{Rng, SeedableRng};
use ruvllm::attention::GraphAttentionEngine;
use ruvllm::config::EmbeddingConfig;
use ruvllm::memory::SubGraph;
use ruvllm::types::{EdgeType, MemoryEdge, MemoryNode, NodeType};
use std::collections::HashMap;
fn create_random_node(id: &str, dim: usize, seed: u64) -> MemoryNode {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
let mut vec: Vec<f32> = (0..dim).map(|_| rng.gen::<f32>() - 0.5).collect();
let norm: f32 = vec.iter().map(|x| x * x).sum::<f32>().sqrt();
vec.iter_mut().for_each(|x| *x /= norm);
MemoryNode {
id: id.into(),
vector: vec,
text: format!("Node {}", id),
node_type: NodeType::Document,
source: "bench".into(),
metadata: HashMap::new(),
}
}
fn create_subgraph(num_nodes: usize, num_edges: usize, dim: usize) -> SubGraph {
let nodes: Vec<MemoryNode> = (0..num_nodes)
.map(|i| create_random_node(&format!("n-{}", i), dim, i as u64))
.collect();
let edges: Vec<MemoryEdge> = (0..num_edges.min(num_nodes.saturating_sub(1)))
.map(|i| MemoryEdge {
id: format!("e-{}", i),
src: format!("n-{}", i),
dst: format!("n-{}", (i + 1) % num_nodes),
edge_type: EdgeType::Follows,
weight: 0.8,
metadata: HashMap::new(),
})
.collect();
SubGraph {
nodes,
edges,
center_ids: vec!["n-0".into()],
}
}
fn benchmark_attention_forward(c: &mut Criterion) {
let config = EmbeddingConfig::default();
let engine = GraphAttentionEngine::new(&config).unwrap();
let query = vec![0.1f32; config.dimension];
let subgraph = create_subgraph(10, 9, config.dimension);
c.bench_function("attention_forward_10_nodes", |b| {
b.iter(|| black_box(engine.attend(&query, &subgraph).unwrap()))
});
}
fn benchmark_attention_varying_nodes(c: &mut Criterion) {
let config = EmbeddingConfig::default();
let engine = GraphAttentionEngine::new(&config).unwrap();
let query = vec![0.1f32; config.dimension];
let mut group = c.benchmark_group("attention_nodes");
for num_nodes in [5, 10, 20, 50, 100] {
let subgraph = create_subgraph(num_nodes, num_nodes - 1, config.dimension);
group.bench_with_input(
BenchmarkId::from_parameter(num_nodes),
&subgraph,
|b, subgraph| b.iter(|| black_box(engine.attend(&query, subgraph).unwrap())),
);
}
group.finish();
}
fn benchmark_attention_varying_edges(c: &mut Criterion) {
let config = EmbeddingConfig::default();
let engine = GraphAttentionEngine::new(&config).unwrap();
let query = vec![0.1f32; config.dimension];
let mut group = c.benchmark_group("attention_edges");
for num_edges in [0, 10, 25, 50, 100] {
let subgraph = create_subgraph(50, num_edges, config.dimension);
group.bench_with_input(
BenchmarkId::from_parameter(num_edges),
&subgraph,
|b, subgraph| b.iter(|| black_box(engine.attend(&query, subgraph).unwrap())),
);
}
group.finish();
}
fn benchmark_attention_varying_dims(c: &mut Criterion) {
let mut group = c.benchmark_group("attention_dimension");
for dim in [128, 256, 512, 768, 1024] {
let config = EmbeddingConfig {
dimension: dim,
..EmbeddingConfig::default()
};
let engine = GraphAttentionEngine::new(&config).unwrap();
let query = vec![0.1f32; dim];
let subgraph = create_subgraph(20, 19, dim);
group.bench_with_input(
BenchmarkId::from_parameter(dim),
&subgraph,
|b, subgraph| b.iter(|| black_box(engine.attend(&query, subgraph).unwrap())),
);
}
group.finish();
}
fn benchmark_cross_attention(c: &mut Criterion) {
let config = EmbeddingConfig::default();
let engine = GraphAttentionEngine::new(&config).unwrap();
let query = vec![0.1f32; config.dimension];
let subgraph = create_subgraph(20, 19, config.dimension);
c.bench_function("cross_attention_20_nodes", |b| {
b.iter(|| black_box(engine.cross_attend(&query, &subgraph).unwrap()))
});
}
fn benchmark_attention_empty_graph(c: &mut Criterion) {
let config = EmbeddingConfig::default();
let engine = GraphAttentionEngine::new(&config).unwrap();
let query = vec![0.1f32; config.dimension];
let subgraph = SubGraph {
nodes: vec![],
edges: vec![],
center_ids: vec![],
};
c.bench_function("attention_empty_graph", |b| {
b.iter(|| black_box(engine.attend(&query, &subgraph).unwrap()))
});
}
criterion_group!(
benches,
benchmark_attention_forward,
benchmark_attention_varying_nodes,
benchmark_attention_varying_edges,
benchmark_attention_varying_dims,
benchmark_cross_attention,
benchmark_attention_empty_graph,
);
criterion_main!(benches);

View File

@@ -0,0 +1,222 @@
//! Memory service benchmarks for RuvLLM
//!
//! Benchmarks HNSW insertion, search, and graph operations.
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use rand::{Rng, SeedableRng};
use ruvllm::config::MemoryConfig;
use ruvllm::memory::MemoryService;
use ruvllm::types::{EdgeType, MemoryEdge, MemoryNode, NodeType};
use std::collections::HashMap;
use tokio::runtime::Runtime;
fn create_random_node(id: &str, dim: usize, seed: u64) -> MemoryNode {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
let mut vec: Vec<f32> = (0..dim).map(|_| rng.gen::<f32>() - 0.5).collect();
let norm: f32 = vec.iter().map(|x| x * x).sum::<f32>().sqrt();
vec.iter_mut().for_each(|x| *x /= norm);
MemoryNode {
id: id.into(),
vector: vec,
text: format!("Node {}", id),
node_type: NodeType::Document,
source: "bench".into(),
metadata: HashMap::new(),
}
}
fn benchmark_memory_insert(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
let mut counter = 0u64;
c.bench_function("memory_insert_single", |b| {
b.iter(|| {
counter += 1;
let node = create_random_node(&format!("bench-{}", counter), 768, counter);
black_box(memory.insert_node(node).unwrap())
})
});
}
fn benchmark_memory_insert_batch(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("memory_insert_batch");
for batch_size in [10, 50, 100, 500] {
group.throughput(Throughput::Elements(batch_size as u64));
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
let nodes: Vec<MemoryNode> = (0..batch_size)
.map(|i| create_random_node(&format!("batch-{}", i), 768, i as u64))
.collect();
group.bench_with_input(
BenchmarkId::from_parameter(batch_size),
&nodes,
|b, nodes| {
b.iter(|| {
for node in nodes.clone() {
black_box(memory.insert_node(node).unwrap());
}
})
},
);
}
group.finish();
}
fn benchmark_memory_search(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
// Pre-populate with nodes
for i in 0..1000 {
let node = create_random_node(&format!("search-{}", i), 768, i as u64);
memory.insert_node(node).unwrap();
}
let query = vec![0.1f32; 768];
c.bench_function("memory_search_k10_1000", |b| {
b.to_async(&rt).iter(|| async {
black_box(memory.search_with_graph(&query, 10, 64, 0).await.unwrap())
})
});
}
fn benchmark_memory_search_varying_k(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
// Pre-populate
for i in 0..1000 {
let node = create_random_node(&format!("k-{}", i), 768, i as u64);
memory.insert_node(node).unwrap();
}
let query = vec![0.1f32; 768];
let mut group = c.benchmark_group("memory_search_k");
for k in [1, 5, 10, 20, 50, 100] {
group.bench_with_input(BenchmarkId::from_parameter(k), &k, |b, &k| {
b.to_async(&rt).iter(|| async {
black_box(memory.search_with_graph(&query, k, 64, 0).await.unwrap())
})
});
}
group.finish();
}
fn benchmark_memory_search_varying_ef(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
// Pre-populate
for i in 0..1000 {
let node = create_random_node(&format!("ef-{}", i), 768, i as u64);
memory.insert_node(node).unwrap();
}
let query = vec![0.1f32; 768];
let mut group = c.benchmark_group("memory_search_ef");
for ef in [16, 32, 64, 128, 256] {
group.bench_with_input(BenchmarkId::from_parameter(ef), &ef, |b, &ef| {
b.to_async(&rt).iter(|| async {
black_box(memory.search_with_graph(&query, 10, ef, 0).await.unwrap())
})
});
}
group.finish();
}
fn benchmark_memory_search_with_graph(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
// Pre-populate with nodes and edges
for i in 0..500 {
let node = create_random_node(&format!("graph-{}", i), 768, i as u64);
memory.insert_node(node).unwrap();
}
for i in 0..499 {
let edge = MemoryEdge {
id: format!("edge-{}", i),
src: format!("graph-{}", i),
dst: format!("graph-{}", i + 1),
edge_type: EdgeType::Follows,
weight: 0.8,
metadata: HashMap::new(),
};
memory.insert_edge(edge).unwrap();
}
let query = vec![0.1f32; 768];
let mut group = c.benchmark_group("memory_search_hops");
for hops in [0, 1, 2, 3] {
group.bench_with_input(BenchmarkId::from_parameter(hops), &hops, |b, &hops| {
b.to_async(&rt).iter(|| async {
black_box(
memory
.search_with_graph(&query, 10, 64, hops)
.await
.unwrap(),
)
})
});
}
group.finish();
}
fn benchmark_memory_scaling(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("memory_scaling");
for num_nodes in [100, 500, 1000, 5000] {
let config = MemoryConfig::default();
let memory = rt.block_on(MemoryService::new(&config)).unwrap();
// Pre-populate
for i in 0..num_nodes {
let node = create_random_node(&format!("scale-{}", i), 768, i as u64);
memory.insert_node(node).unwrap();
}
let query = vec![0.1f32; 768];
group.bench_with_input(
BenchmarkId::from_parameter(num_nodes),
&num_nodes,
|b, _| {
b.to_async(&rt).iter(|| async {
black_box(memory.search_with_graph(&query, 10, 64, 0).await.unwrap())
})
},
);
}
group.finish();
}
criterion_group!(
benches,
benchmark_memory_insert,
benchmark_memory_insert_batch,
benchmark_memory_search,
benchmark_memory_search_varying_k,
benchmark_memory_search_varying_ef,
benchmark_memory_search_with_graph,
benchmark_memory_scaling,
);
criterion_main!(benches);

View File

@@ -0,0 +1,124 @@
//! Pipeline benchmarks for RuvLLM
//!
//! Benchmarks the complete request-to-response pipeline.
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use ruvllm::{Config, Request, RuvLLM};
use tokio::runtime::Runtime;
fn benchmark_query(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = Config::builder()
.embedding_dim(128)
.router_hidden_dim(32)
.learning_enabled(false)
.build()
.unwrap();
let llm = rt.block_on(RuvLLM::new(config)).unwrap();
c.bench_function("query_simple", |b| {
b.to_async(&rt)
.iter(|| async { black_box(llm.query("What is Rust?").await.unwrap()) })
});
}
fn benchmark_query_lengths(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = Config::builder()
.embedding_dim(128)
.router_hidden_dim(32)
.learning_enabled(false)
.build()
.unwrap();
let llm = rt.block_on(RuvLLM::new(config)).unwrap();
let queries = vec![
("short", "Hi"),
("medium", "What is machine learning and how does it work?"),
("long", "Please explain in detail how neural networks process information, including concepts like forward propagation, backpropagation, gradient descent, and the role of activation functions in learning complex patterns from data."),
];
let mut group = c.benchmark_group("query_by_length");
for (name, query) in queries {
group.bench_with_input(BenchmarkId::from_parameter(name), &query, |b, query| {
b.to_async(&rt)
.iter(|| async { black_box(llm.query(*query).await.unwrap()) })
});
}
group.finish();
}
fn benchmark_concurrent_queries(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = Config::builder()
.embedding_dim(128)
.router_hidden_dim(32)
.learning_enabled(false)
.build()
.unwrap();
let llm = std::sync::Arc::new(rt.block_on(RuvLLM::new(config)).unwrap());
let mut group = c.benchmark_group("concurrent_queries");
for concurrency in [1, 2, 4, 8] {
group.bench_with_input(
BenchmarkId::from_parameter(concurrency),
&concurrency,
|b, &concurrency| {
b.to_async(&rt).iter(|| async {
let mut handles = Vec::new();
for _ in 0..concurrency {
let llm_clone = llm.clone();
handles.push(tokio::spawn(async move {
llm_clone.query("Test query").await.unwrap()
}));
}
for handle in handles {
black_box(handle.await.unwrap());
}
})
},
);
}
group.finish();
}
fn benchmark_session(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let config = Config::builder()
.embedding_dim(128)
.router_hidden_dim(32)
.learning_enabled(false)
.build()
.unwrap();
let llm = rt.block_on(RuvLLM::new(config)).unwrap();
c.bench_function("session_multi_turn", |b| {
b.to_async(&rt).iter(|| async {
let session = llm.new_session();
black_box(llm.query_session(&session, "First question").await.unwrap());
black_box(llm.query_session(&session, "Follow up").await.unwrap());
black_box(
llm.query_session(&session, "Another follow up")
.await
.unwrap(),
);
})
});
}
criterion_group!(
benches,
benchmark_query,
benchmark_query_lengths,
benchmark_concurrent_queries,
benchmark_session,
);
criterion_main!(benches);

View File

@@ -0,0 +1,150 @@
//! Router benchmarks for RuvLLM
//!
//! Benchmarks FastGRNN router forward pass and training.
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use ruvllm::config::RouterConfig;
use ruvllm::router::FastGRNNRouter;
use ruvllm::types::RouterSample;
fn benchmark_router_forward(c: &mut Criterion) {
let config = RouterConfig::default();
let router = FastGRNNRouter::new(&config).unwrap();
let features = vec![0.1f32; config.input_dim];
let hidden = vec![0.0f32; config.hidden_dim];
c.bench_function("router_forward", |b| {
b.iter(|| black_box(router.forward(&features, &hidden).unwrap()))
});
}
fn benchmark_router_forward_batch_sizes(c: &mut Criterion) {
let config = RouterConfig::default();
let router = FastGRNNRouter::new(&config).unwrap();
let hidden = vec![0.0f32; config.hidden_dim];
let mut group = c.benchmark_group("router_forward_features");
for feature_dim in [64, 128, 256, 512] {
let config = RouterConfig {
input_dim: feature_dim,
..RouterConfig::default()
};
let router = FastGRNNRouter::new(&config).unwrap();
let features = vec![0.1f32; feature_dim];
group.bench_with_input(
BenchmarkId::from_parameter(feature_dim),
&features,
|b, features| b.iter(|| black_box(router.forward(features, &hidden).unwrap())),
);
}
group.finish();
}
fn benchmark_router_training(c: &mut Criterion) {
let config = RouterConfig::default();
let mut router = FastGRNNRouter::new(&config).unwrap();
let samples: Vec<RouterSample> = (0..32)
.map(|i| RouterSample {
features: vec![0.1; config.input_dim],
label_model: i % 4,
label_context: i % 5,
label_temperature: 0.7,
label_top_p: 0.9,
quality: 0.8,
latency_ms: 100.0,
})
.collect();
c.bench_function("router_train_batch_32", |b| {
b.iter(|| black_box(router.train_batch(&samples, 0.001, 0.0, None, None)))
});
}
fn benchmark_router_training_batch_sizes(c: &mut Criterion) {
let config = RouterConfig::default();
let mut group = c.benchmark_group("router_train_batch");
for batch_size in [8, 16, 32, 64, 128] {
let mut router = FastGRNNRouter::new(&config).unwrap();
let samples: Vec<RouterSample> = (0..batch_size)
.map(|i| RouterSample {
features: vec![0.1; config.input_dim],
label_model: i % 4,
label_context: i % 5,
label_temperature: 0.7,
label_top_p: 0.9,
quality: 0.8,
latency_ms: 100.0,
})
.collect();
group.bench_with_input(
BenchmarkId::from_parameter(batch_size),
&samples,
|b, samples| b.iter(|| black_box(router.train_batch(samples, 0.001, 0.0, None, None))),
);
}
group.finish();
}
fn benchmark_router_ewc(c: &mut Criterion) {
let config = RouterConfig::default();
let mut router = FastGRNNRouter::new(&config).unwrap();
let samples: Vec<RouterSample> = (0..32)
.map(|i| RouterSample {
features: vec![0.1; config.input_dim],
label_model: i % 4,
label_context: i % 5,
label_temperature: 0.7,
label_top_p: 0.9,
quality: 0.8,
latency_ms: 100.0,
})
.collect();
// Pre-compute Fisher and optimal weights
let fisher = router.compute_fisher(&samples);
let optimal = router.get_weights();
c.bench_function("router_train_with_ewc", |b| {
b.iter(|| {
black_box(router.train_batch(&samples, 0.001, 0.4, Some(&fisher), Some(&optimal)))
})
});
}
fn benchmark_fisher_computation(c: &mut Criterion) {
let config = RouterConfig::default();
let router = FastGRNNRouter::new(&config).unwrap();
let samples: Vec<RouterSample> = (0..100)
.map(|i| RouterSample {
features: vec![0.1; config.input_dim],
label_model: i % 4,
label_context: i % 5,
label_temperature: 0.7,
label_top_p: 0.9,
quality: 0.8,
latency_ms: 100.0,
})
.collect();
c.bench_function("router_compute_fisher_100", |b| {
b.iter(|| black_box(router.compute_fisher(&samples)))
});
}
criterion_group!(
benches,
benchmark_router_forward,
benchmark_router_forward_batch_sizes,
benchmark_router_training,
benchmark_router_training_batch_sizes,
benchmark_router_ewc,
benchmark_fisher_computation,
);
criterion_main!(benches);

View File

@@ -0,0 +1,579 @@
//! SONA (Self-Optimizing Neural Architecture) Performance Benchmarks
//!
//! Comprehensive benchmarks for all SONA components:
//! - MicroLoRA forward pass (target: <100μs)
//! - Trajectory recording (target: <1μs per step)
//! - ReasoningBank pattern extraction
//! - InstantLoop full cycle (target: <1ms)
//! - EWC++ loss computation
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use ruvllm::sona::*;
// ============================================================================
// MicroLoRA Benchmarks
// ============================================================================
fn micro_lora_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("micro_lora");
// Test different hidden dimensions
for dim in [128, 256, 512] {
group.throughput(Throughput::Elements(dim as u64));
// Rank 1 benchmarks
group.bench_with_input(BenchmarkId::new("forward_rank1", dim), &dim, |b, &dim| {
let lora = MicroLoRA::new(dim, 1);
let input = vec![1.0f32; dim];
let mut output = vec![0.0f32; dim];
b.iter(|| {
lora.forward(black_box(&input), black_box(&mut output));
});
});
// Rank 2 benchmarks
group.bench_with_input(BenchmarkId::new("forward_rank2", dim), &dim, |b, &dim| {
let lora = MicroLoRA::new(dim, 2);
let input = vec![1.0f32; dim];
let mut output = vec![0.0f32; dim];
b.iter(|| {
lora.forward(black_box(&input), black_box(&mut output));
});
});
// Scalar (non-SIMD) forward pass for comparison
group.bench_with_input(BenchmarkId::new("forward_scalar", dim), &dim, |b, &dim| {
let lora = MicroLoRA::new(dim, 1);
let input = vec![1.0f32; dim];
let mut output = vec![0.0f32; dim];
b.iter(|| {
lora.forward_scalar(black_box(&input), black_box(&mut output));
});
});
// Gradient accumulation
group.bench_with_input(
BenchmarkId::new("accumulate_gradient", dim),
&dim,
|b, &dim| {
let mut lora = MicroLoRA::new(dim, 1);
let signal = LearningSignal::with_gradient(vec![0.5; dim], vec![0.1; dim], 0.8);
b.iter(|| {
lora.accumulate_gradient(black_box(&signal));
});
},
);
// Apply accumulated gradients
group.bench_with_input(
BenchmarkId::new("apply_accumulated", dim),
&dim,
|b, &dim| {
let mut lora = MicroLoRA::new(dim, 1);
// Pre-accumulate some gradients
let signal = LearningSignal::with_gradient(vec![0.5; dim], vec![0.1; dim], 0.8);
for _ in 0..10 {
lora.accumulate_gradient(&signal);
}
b.iter(|| {
lora.apply_accumulated(black_box(0.001));
});
},
);
}
group.finish();
}
// ============================================================================
// Trajectory Recording Benchmarks
// ============================================================================
fn trajectory_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("trajectory");
// Single step recording
group.bench_function("record_step", |b| {
let buffer = TrajectoryBuffer::new(10000);
let id_gen = TrajectoryIdGen::new();
b.iter(|| {
let trajectory = QueryTrajectory::new(id_gen.next(), vec![0.1, 0.2, 0.3, 0.4]);
buffer.record(black_box(trajectory));
});
});
// Builder - complete trajectory construction
for steps in [5, 10, 20] {
group.bench_with_input(
BenchmarkId::new("build_trajectory", steps),
&steps,
|b, &steps| {
b.iter(|| {
let mut builder = TrajectoryBuilder::new(1, vec![0.1, 0.2, 0.3, 0.4]);
for i in 0..steps {
builder.add_step(vec![0.5; 128], vec![0.3; 64], 0.7);
}
black_box(builder.build(0.85));
});
},
);
}
// Drain operations
group.bench_function("drain_all", |b| {
let buffer = TrajectoryBuffer::new(10000);
// Pre-fill buffer
for i in 0..1000 {
buffer.record(QueryTrajectory::new(i, vec![0.1, 0.2]));
}
b.iter(|| {
let drained = buffer.drain();
black_box(drained);
// Refill for next iteration
for i in 0..1000 {
buffer.record(QueryTrajectory::new(i, vec![0.1, 0.2]));
}
});
});
group.bench_function("drain_batch_100", |b| {
let buffer = TrajectoryBuffer::new(10000);
// Pre-fill buffer
for i in 0..1000 {
buffer.record(QueryTrajectory::new(i, vec![0.1, 0.2]));
}
b.iter(|| {
let drained = buffer.drain_n(100);
black_box(drained);
// Refill what we drained
for i in 0..100 {
buffer.record(QueryTrajectory::new(i, vec![0.1, 0.2]));
}
});
});
group.finish();
}
// ============================================================================
// ReasoningBank Benchmarks
// ============================================================================
fn reasoning_bank_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("reasoning_bank");
// Pattern extraction with K-means++
for trajectory_count in [100, 500, 1000] {
group.bench_with_input(
BenchmarkId::new("extract_patterns", trajectory_count),
&trajectory_count,
|b, &count| {
let config = PatternConfig {
k_clusters: 10,
embedding_dim: 128,
max_iterations: 50,
min_cluster_size: 3,
quality_threshold: 0.5,
..Default::default()
};
let mut bank = ReasoningBank::new(config);
// Add trajectories
for i in 0..count {
let mut trajectory = QueryTrajectory::new(
i,
vec![
(i as f32 * 0.1) % 1.0,
(i as f32 * 0.2) % 1.0,
(i as f32 * 0.3) % 1.0,
],
);
trajectory.finalize(0.7 + (i as f32 * 0.001) % 0.3, 1000);
bank.add_trajectory(&trajectory);
}
b.iter(|| {
let patterns = bank.extract_patterns();
black_box(patterns);
});
},
);
}
// Query similar patterns
group.bench_function("query_patterns", |b| {
let config = PatternConfig {
k_clusters: 20,
embedding_dim: 128,
min_cluster_size: 3,
quality_threshold: 0.5,
..Default::default()
};
let mut bank = ReasoningBank::new(config);
// Build up pattern database
for i in 0..1000 {
let mut trajectory = QueryTrajectory::new(i, vec![(i as f32 * 0.1) % 1.0; 128]);
trajectory.finalize(0.8, 1000);
bank.add_trajectory(&trajectory);
}
bank.extract_patterns();
let query = vec![0.5; 128];
b.iter(|| {
let similar = bank.find_similar(black_box(&query), 5);
black_box(similar);
});
});
// Pattern consolidation
group.bench_function("consolidate_patterns", |b| {
let config = PatternConfig {
k_clusters: 30,
embedding_dim: 128,
min_cluster_size: 2,
quality_threshold: 0.4,
..Default::default()
};
let mut bank = ReasoningBank::new(config);
// Create many similar patterns
for i in 0..500 {
let mut trajectory = QueryTrajectory::new(i, vec![1.0 + (i as f32 * 0.001); 128]);
trajectory.finalize(0.8, 1000);
bank.add_trajectory(&trajectory);
}
bank.extract_patterns();
b.iter(|| {
let mut bank_clone = bank.clone();
bank_clone.consolidate(black_box(0.95));
});
});
group.finish();
}
// ============================================================================
// EWC++ Benchmarks
// ============================================================================
fn ewc_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("ewc_plus_plus");
// Fisher information update
for param_count in [256, 512, 1024] {
group.bench_with_input(
BenchmarkId::new("update_fisher", param_count),
&param_count,
|b, &count| {
let config = EwcConfig {
param_count: count,
..Default::default()
};
let mut ewc = EwcPlusPlus::new(config);
let gradients = vec![0.1; count];
b.iter(|| {
ewc.update_fisher(black_box(&gradients));
});
},
);
}
// Task boundary detection
group.bench_function("detect_boundary", |b| {
let config = EwcConfig {
param_count: 512,
gradient_history_size: 100,
..Default::default()
};
let mut ewc = EwcPlusPlus::new(config);
// Build up history
for _ in 0..100 {
ewc.update_fisher(&vec![0.1; 512]);
}
let test_gradients = vec![0.15; 512];
b.iter(|| {
let is_boundary = ewc.detect_task_boundary(black_box(&test_gradients));
black_box(is_boundary);
});
});
// Apply constraints
for task_count in [1, 5, 10] {
group.bench_with_input(
BenchmarkId::new("apply_constraints", task_count),
&task_count,
|b, &tasks| {
let config = EwcConfig {
param_count: 512,
max_tasks: tasks,
..Default::default()
};
let mut ewc = EwcPlusPlus::new(config);
// Create multiple tasks
for _ in 0..tasks {
for _ in 0..50 {
ewc.update_fisher(&vec![0.1; 512]);
}
ewc.start_new_task();
}
let gradients = vec![0.5; 512];
b.iter(|| {
let constrained = ewc.apply_constraints(black_box(&gradients));
black_box(constrained);
});
},
);
}
// Regularization loss computation
group.bench_function("regularization_loss", |b| {
let config = EwcConfig {
param_count: 512,
max_tasks: 5,
initial_lambda: 1000.0,
..Default::default()
};
let mut ewc = EwcPlusPlus::new(config);
// Create tasks
for _ in 0..5 {
ewc.set_optimal_weights(&vec![0.0; 512]);
for _ in 0..50 {
ewc.update_fisher(&vec![0.1; 512]);
}
ewc.start_new_task();
}
let current_weights = vec![0.1; 512];
b.iter(|| {
let loss = ewc.regularization_loss(black_box(&current_weights));
black_box(loss);
});
});
// Task consolidation
group.bench_function("consolidate_tasks", |b| {
let config = EwcConfig {
param_count: 512,
max_tasks: 10,
..Default::default()
};
b.iter(|| {
let mut ewc = EwcPlusPlus::new(config.clone());
// Create 10 tasks
for _ in 0..10 {
for _ in 0..20 {
ewc.update_fisher(&vec![0.1; 512]);
}
ewc.start_new_task();
}
ewc.consolidate_all_tasks();
black_box(ewc.task_count());
});
});
group.finish();
}
// ============================================================================
// Integrated Benchmarks (Complete SONA Cycles)
// ============================================================================
fn integrated_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("integrated");
// Complete instant learning cycle
group.bench_function("instant_loop_full_cycle", |b| {
let dim = 256;
let mut lora = MicroLoRA::new(dim, 1);
let buffer = TrajectoryBuffer::new(1000);
let id_gen = TrajectoryIdGen::new();
b.iter(|| {
// 1. Record trajectory (simulate 10 steps)
let mut builder = TrajectoryBuilder::new(id_gen.next(), vec![0.5; dim]);
for i in 0..10 {
builder.add_step(vec![0.3; dim], vec![0.2; 128], 0.7 + (i as f32 * 0.02));
}
let trajectory = builder.build(0.85);
// 2. Convert to learning signal
let signal = LearningSignal::from_trajectory(&trajectory);
// 3. Accumulate gradient
lora.accumulate_gradient(&signal);
// 4. Apply if batch ready (every 10 iterations in real use)
if lora.pending_updates() >= 10 {
lora.apply_accumulated(0.001);
}
// 5. Store trajectory
buffer.record(black_box(trajectory));
});
});
// Pattern-based learning cycle
group.bench_function("pattern_learning_cycle", |b| {
let config = PatternConfig {
k_clusters: 10,
embedding_dim: 128,
min_cluster_size: 3,
quality_threshold: 0.6,
..Default::default()
};
let mut bank = ReasoningBank::new(config);
// Pre-populate with some trajectories
for i in 0..100 {
let mut trajectory = QueryTrajectory::new(i, vec![0.5; 128]);
trajectory.finalize(0.8, 1000);
bank.add_trajectory(&trajectory);
}
b.iter(|| {
// 1. Add new trajectory
let mut trajectory = QueryTrajectory::new(1000, vec![0.6; 128]);
trajectory.finalize(0.85, 1000);
bank.add_trajectory(&trajectory);
// 2. Extract patterns (would be done periodically)
if bank.trajectory_count() % 50 == 0 {
let patterns = bank.extract_patterns();
black_box(patterns);
}
// 3. Query similar patterns
let query = vec![0.6; 128];
let similar = bank.find_similar(&query, 3);
black_box(similar);
});
});
// EWC-protected learning
group.bench_function("ewc_protected_learning", |b| {
let param_count = 512;
let config = EwcConfig {
param_count,
max_tasks: 5,
initial_lambda: 1000.0,
..Default::default()
};
let mut ewc = EwcPlusPlus::new(config);
// Setup with one completed task
ewc.set_optimal_weights(&vec![0.0; param_count]);
for _ in 0..50 {
ewc.update_fisher(&vec![0.1; param_count]);
}
ewc.start_new_task();
let mut lora = MicroLoRA::new(param_count, 1);
b.iter(|| {
// 1. Get raw gradients from learning signal
let signal =
LearningSignal::with_gradient(vec![0.5; param_count], vec![0.1; param_count], 0.8);
// 2. Apply EWC constraints
let constrained = ewc.apply_constraints(&signal.gradient_estimate);
// 3. Create constrained signal
let constrained_signal = LearningSignal::with_gradient(
signal.query_embedding.clone(),
constrained,
signal.quality_score,
);
// 4. Apply to LoRA
lora.accumulate_gradient(&constrained_signal);
// 5. Update Fisher
ewc.update_fisher(&signal.gradient_estimate);
});
});
group.finish();
}
// ============================================================================
// Learning Signal Benchmarks
// ============================================================================
fn learning_signal_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("learning_signal");
// Gradient estimation from trajectory
for step_count in [5, 10, 20] {
group.bench_with_input(
BenchmarkId::new("from_trajectory", step_count),
&step_count,
|b, &steps| {
let mut trajectory = QueryTrajectory::new(1, vec![0.5; 256]);
for i in 0..steps {
trajectory.add_step(TrajectoryStep::new(
vec![0.3; 256],
vec![0.2; 128],
0.7 + (i as f32 * 0.02),
i,
));
}
trajectory.finalize(0.85, 1000);
b.iter(|| {
let signal = LearningSignal::from_trajectory(black_box(&trajectory));
black_box(signal);
});
},
);
}
group.finish();
}
criterion_group!(
benches,
micro_lora_benchmarks,
trajectory_benchmarks,
reasoning_bank_benchmarks,
ewc_benchmarks,
integrated_benchmarks,
learning_signal_benchmarks,
);
criterion_main!(benches);