use graph_d::{Graph, Result};
use serde_json::json;
use std::time::Instant;
fn main() -> Result<()> {
println!("=== Graph Database Performance Test ===\n");
let test_sizes = vec![1_000, 10_000, 100_000];
for &size in &test_sizes {
println!("Testing with {size} nodes...");
test_graph_performance(size)?;
println!();
}
println!("=== Memory Efficiency Test ===");
test_memory_efficiency()?;
Ok(())
}
fn test_graph_performance(node_count: usize) -> Result<()> {
let start = Instant::now();
let mut graph = Graph::new()?;
println!(" Graph initialization: {:?}", start.elapsed());
let node_start = Instant::now();
let mut node_ids = Vec::with_capacity(node_count);
for i in 0..node_count {
let properties = [
("id".to_string(), json!(i)),
("name".to_string(), json!(format!("Node_{}", i))),
(
"type".to_string(),
json!(if i % 2 == 0 { "even" } else { "odd" }),
),
("category".to_string(), json!(i % 100)),
("score".to_string(), json!(i as f64 * 0.123)),
(
"metadata".to_string(),
json!({
"created_at": "2024-01-01",
"version": 1,
"tags": [format!("tag_{}", i % 10)]
}),
),
]
.into();
let node_id = graph.create_node(properties)?;
node_ids.push(node_id);
}
let node_duration = node_start.elapsed();
println!(" Node creation ({node_count} nodes): {node_duration:?}");
println!(
" Nodes per second: {:.0}",
node_count as f64 / node_duration.as_secs_f64()
);
let rel_start = Instant::now();
let rel_count = std::cmp::min(node_count * 2, 50_000);
for i in 0..rel_count {
let from_idx = i % node_count;
let to_idx = (i + 1) % node_count;
let properties = [
("weight".to_string(), json!(i as f64 / 1000.0)),
("created".to_string(), json!("2024-01-01")),
]
.into();
graph.create_relationship(
node_ids[from_idx],
node_ids[to_idx],
"CONNECTS".to_string(),
properties,
)?;
}
let rel_duration = rel_start.elapsed();
println!(" Relationship creation ({rel_count} rels): {rel_duration:?}");
println!(
" Relationships per second: {:.0}",
rel_count as f64 / rel_duration.as_secs_f64()
);
let read_start = Instant::now();
let read_operations = std::cmp::min(1000, node_count);
for i in 0..read_operations {
let node_id = node_ids[i % node_count];
let _node = graph.get_node(node_id)?;
let _rels = graph.get_relationships_for_node(node_id)?;
}
let read_duration = read_start.elapsed();
println!(" Read operations ({read_operations}): {read_duration:?}");
println!(
" Reads per second: {:.0}",
read_operations as f64 / read_duration.as_secs_f64()
);
let total_duration = start.elapsed();
println!(" Total time: {total_duration:?}");
println!(
" Final graph size: {} nodes, {} relationships",
graph.storage.node_count(),
graph.storage.relationship_count()
);
Ok(())
}
fn test_memory_efficiency() -> Result<()> {
println!("Testing memory efficiency with realistic data sizes...");
let start = Instant::now();
let mut graph = Graph::new()?;
const NODES: usize = 50_000;
const RELS_PER_NODE: usize = 4;
println!(" Creating {NODES} nodes with rich properties...");
let mut node_ids = Vec::with_capacity(NODES);
for i in 0..NODES {
let properties = [
("id".to_string(), json!(i)),
("name".to_string(), json!(format!("User_{}", i))),
("email".to_string(), json!(format!("user{}@example.com", i))),
("age".to_string(), json!(20 + (i % 60))),
("location".to_string(), json!(format!("City_{}", i % 1000))),
("interests".to_string(), json!(vec![
format!("interest_{}", i % 20),
format!("hobby_{}", (i * 3) % 15)
])),
("profile".to_string(), json!({
"bio": format!("This is user {} with some biographical information that takes up space", i),
"settings": {
"notifications": true,
"privacy": "public",
"theme": if i % 2 == 0 { "dark" } else { "light" }
},
"stats": {
"posts": i % 100,
"followers": i % 1000,
"following": (i * 2) % 500
}
})),
].into();
let node_id = graph.create_node(properties)?;
node_ids.push(node_id);
}
println!(" Node creation completed in {:?}", start.elapsed());
let rel_start = Instant::now();
for i in 0..NODES {
for j in 1..=RELS_PER_NODE {
if i + j < NODES {
let properties = [
(
"type".to_string(),
json!(match j {
1 => "FOLLOWS",
2 => "FRIENDS_WITH",
3 => "WORKS_WITH",
_ => "KNOWS",
}),
),
(
"strength".to_string(),
json!(j as f64 / RELS_PER_NODE as f64),
),
(
"since".to_string(),
json!(format!("2024-{:02}-01", (i % 12) + 1)),
),
]
.into();
graph.create_relationship(
node_ids[i],
node_ids[i + j],
"SOCIAL".to_string(),
properties,
)?;
}
}
}
println!(
" Relationship creation completed in {:?}",
rel_start.elapsed()
);
let query_start = Instant::now();
let mut total_results = 0;
for i in (0..NODES).step_by(1000) {
let node_id = node_ids[i];
let _node = graph.get_node(node_id)?;
let rels = graph.get_relationships_for_node(node_id)?;
total_results += rels.len();
}
println!(
" Query performance test completed in {:?}",
query_start.elapsed()
);
println!(
" Average relationships per sampled node: {:.1}",
total_results as f64 / (NODES / 1000) as f64
);
let total_time = start.elapsed();
println!(" Total test time: {total_time:?}");
println!(
" Final size: {} nodes, {} relationships",
graph.storage.node_count(),
graph.storage.relationship_count()
);
let estimated_memory_mb = estimate_memory_usage(&graph);
println!(" Estimated memory usage: {estimated_memory_mb:.1} MB");
println!(
" Memory per node: {:.1} KB",
(estimated_memory_mb * 1024.0) / NODES as f64
);
Ok(())
}
fn estimate_memory_usage(graph: &Graph) -> f64 {
let node_count = graph.storage.node_count();
let rel_count = graph.storage.relationship_count();
let node_memory = node_count as f64 * 500.0;
let rel_memory = rel_count as f64 * 200.0;
let index_overhead = (node_memory + rel_memory) * 0.5;
(node_memory + rel_memory + index_overhead) / (1024.0 * 1024.0)
}