use criterion::{
black_box, criterion_group, criterion_main, BenchmarkId, Criterion,
Throughput,
};
use mf_model::node_pool::{
NodePool, QueryCacheConfig, LazyQueryConfig, QueryCondition,
};
use mf_model::{Node, Attrs, node_definition::NodeTree};
use std::sync::Arc;
fn create_large_node_pool(node_count: usize) -> Arc<NodePool> {
let mut child_nodes = Vec::new();
for i in 1..node_count {
let node_type = match i % 5 {
0 => "paragraph",
1 => "heading",
2 => "text",
3 => "list_item",
_ => "block",
};
let node = Node::new(
&format!("node_{}", i),
node_type.to_string(),
Attrs::default(),
vec![],
vec![],
);
child_nodes.push(NodeTree(node, vec![]));
}
let root = Node::new(
"root",
"document".to_string(),
Attrs::default(),
(1..node_count).map(|i| format!("node_{}", i).into()).collect(),
vec![],
);
NodePool::from(NodeTree(root, child_nodes))
}
fn bench_query_strategies(c: &mut Criterion) {
let mut group = c.benchmark_group("node_pool_query");
for size in [100, 1000, 10000].iter() {
let pool = create_large_node_pool(*size);
group.throughput(Throughput::Elements(*size as u64));
group.bench_with_input(
BenchmarkId::new("full_scan", size),
size,
|b, _| {
b.iter(|| {
let results = pool.filter_nodes(|node| {
black_box(node.r#type == "paragraph")
});
black_box(results)
});
},
);
group.bench_with_input(
BenchmarkId::new("parallel_query", size),
size,
|b, _| {
b.iter(|| {
let results = pool.parallel_query(|node| {
black_box(node.r#type == "paragraph")
});
black_box(results)
});
},
);
let config = QueryCacheConfig { capacity: 1000, enabled: true };
let opt_engine =
pool.optimized_query(config).expect("创建优化查询引擎失败");
group.bench_with_input(
BenchmarkId::new("optimized_indexed", size),
size,
|b, _| {
b.iter(|| {
let results = opt_engine.by_type("paragraph");
black_box(results)
});
},
);
let lazy_config = LazyQueryConfig {
cache_capacity: 1000,
index_cache_capacity: 100,
cache_enabled: true,
index_build_threshold: 1, };
let mut lazy_engine = pool.lazy_query(lazy_config);
let _ = lazy_engine.by_type_lazy("paragraph");
group.bench_with_input(
BenchmarkId::new("lazy_cached", size),
size,
|b, _| {
b.iter(|| {
let results = lazy_engine.by_type_lazy("paragraph");
black_box(results)
});
},
);
}
group.finish();
}
fn bench_complex_queries(c: &mut Criterion) {
let pool = create_large_node_pool(10000);
let mut group = c.benchmark_group("complex_queries");
group.bench_function("multi_condition_filter", |b| {
b.iter(|| {
let results = pool.filter_nodes(|node| {
black_box(
node.r#type == "paragraph"
&& node.content.len() > 0
&& !node.marks.is_empty(),
)
});
black_box(results)
});
});
group.bench_function("depth_query", |b| {
b.iter(|| {
let results = pool.filter_nodes(|node| {
let depth = pool.get_node_depth(&node.id);
black_box(depth == Some(2))
});
black_box(results)
});
});
let lazy_config = LazyQueryConfig::default();
let mut lazy_engine = pool.lazy_query(lazy_config);
group.bench_function("combined_query", |b| {
b.iter(|| {
let conditions = vec![
QueryCondition::ByType("paragraph".to_string()),
QueryCondition::ByDepth(2),
QueryCondition::HasChildren,
];
let results = lazy_engine.combined_query(&conditions);
black_box(results)
});
});
group.finish();
}
fn bench_hierarchy_operations(c: &mut Criterion) {
let pool = create_large_node_pool(10000);
let mut group = c.benchmark_group("hierarchy_ops");
let test_node_id = "node_5000".into();
group.bench_function("get_ancestors", |b| {
b.iter(|| {
let ancestors = pool.ancestors(&test_node_id);
black_box(ancestors)
});
});
group.bench_function("get_descendants", |b| {
b.iter(|| {
let descendants = pool.descendants(&test_node_id);
black_box(descendants)
});
});
group.bench_function("get_siblings", |b| {
b.iter(|| {
let siblings = pool.get_all_siblings(&test_node_id);
black_box(siblings)
});
});
group.bench_function("get_path", |b| {
b.iter(|| {
let path = pool.get_node_path(&test_node_id);
black_box(path)
});
});
group.bench_function("validate_hierarchy", |b| {
b.iter(|| {
let result = pool.validate_hierarchy();
black_box(result)
});
});
group.finish();
}
fn bench_node_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("node_operations");
let node = Arc::new(Node::new(
"test_node",
"paragraph".to_string(),
Attrs::default(),
vec!["child1".into(), "child2".into(), "child3".into()],
vec![],
));
group.bench_function("node_clone", |b| {
b.iter(|| {
let cloned = (*node).clone();
black_box(cloned)
});
});
group.bench_function("arc_clone", |b| {
b.iter(|| {
let cloned = Arc::clone(&node);
black_box(cloned)
});
});
group.bench_function("update_attr", |b| {
b.iter(|| {
let mut attrs = imbl::HashMap::new();
attrs.insert("key".to_string(), serde_json::json!("value"));
let updated = node.update_attr(attrs);
black_box(updated)
});
});
group.bench_function("insert_content", |b| {
b.iter(|| {
let updated = node.insert_content("new_child");
black_box(updated)
});
});
group.finish();
}
fn bench_cache_effectiveness(c: &mut Criterion) {
let pool = create_large_node_pool(10000);
let mut group = c.benchmark_group("cache_effectiveness");
let lazy_config = LazyQueryConfig {
cache_capacity: 1000,
index_cache_capacity: 100,
cache_enabled: true,
index_build_threshold: 1,
};
let mut lazy_engine = pool.lazy_query(lazy_config);
group.bench_function("cold_query", |b| {
b.iter(|| {
let results = lazy_engine.smart_query("unique_query", || {
pool.parallel_query(|node| node.r#type == "paragraph")
});
black_box(results)
});
});
for _ in 0..10 {
let _ = lazy_engine.by_type_lazy("paragraph");
}
group.bench_function("hot_query", |b| {
b.iter(|| {
let results = lazy_engine.by_type_lazy("paragraph");
black_box(results)
});
});
group.finish();
}
criterion_group!(
benches,
bench_query_strategies,
bench_complex_queries,
bench_hierarchy_operations,
bench_node_operations,
bench_cache_effectiveness,
);
criterion_main!(benches);