208 lines
6.1 KiB
Rust
208 lines
6.1 KiB
Rust
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
|
|
use rtx_geom::layers::{GATLayer, GCNLayer, GNNLayer, GraphSAGELayer};
|
|
use rtx_geom::{AggregationType, Edge, Graph, MessagePassing, Node};
|
|
use rtx_tensor::{Device, Tensor};
|
|
|
|
fn create_test_graph(num_nodes: usize, feature_dim: usize, edge_probability: f32) -> Graph {
|
|
let mut graph = Graph::new();
|
|
let mut nodes = Vec::new();
|
|
let device = Device::cpu();
|
|
|
|
// Add nodes
|
|
for i in 0..num_nodes {
|
|
let mut features = vec![0.0f32; feature_dim];
|
|
for j in 0..feature_dim {
|
|
features[j] = (i * 7 + j * 13) as f32 % 100.0 / 50.0 - 1.0; // [-1, 1] range
|
|
}
|
|
let node = graph.add_node(Node::new(
|
|
Tensor::from_data(features, [feature_dim], &device).unwrap(),
|
|
));
|
|
nodes.push(node);
|
|
}
|
|
|
|
// Add edges based on probability (deterministic for benchmarking)
|
|
for i in 0..num_nodes {
|
|
for j in 0..num_nodes {
|
|
if i != j {
|
|
let hash = (i * 1337 + j * 7919) % 10000;
|
|
if (hash as f32 / 10000.0) < edge_probability {
|
|
let weight = Tensor::from_data(vec![1.0], [1], &device).unwrap();
|
|
let _ = graph.add_edge(nodes[i], nodes[j], Edge::new(weight));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
graph
|
|
}
|
|
|
|
fn bench_graph_creation(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("graph_creation");
|
|
|
|
for &size in &[10, 50, 100, 500] {
|
|
group.throughput(Throughput::Elements(size as u64));
|
|
group.bench_with_input(
|
|
BenchmarkId::new("nodes_and_edges", size),
|
|
&size,
|
|
|b, &size| {
|
|
b.iter(|| create_test_graph(size, 4, 0.1));
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_message_passing(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("message_passing");
|
|
|
|
let graphs: Vec<_> = [10, 50, 100, 200]
|
|
.iter()
|
|
.map(|&size| (size, create_test_graph(size, 8, 0.2)))
|
|
.collect();
|
|
|
|
for (size, graph) in graphs {
|
|
group.throughput(Throughput::Elements(size as u64));
|
|
|
|
// Benchmark different aggregation types
|
|
for &agg_type in &[
|
|
AggregationType::Sum,
|
|
AggregationType::Mean,
|
|
AggregationType::Max,
|
|
AggregationType::WeightedSum,
|
|
] {
|
|
let mp = MessagePassing::new(agg_type);
|
|
group.bench_with_input(
|
|
BenchmarkId::new(format!("{:?}", agg_type), size),
|
|
&(&graph, &mp),
|
|
|b, (graph, mp)| {
|
|
b.iter(|| mp.compute_messages(graph));
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_gcn_layer(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("gcn_layer");
|
|
|
|
let test_cases = vec![
|
|
(10, 4, 8), // small graph
|
|
(50, 8, 16), // medium graph
|
|
(100, 16, 32), // large graph
|
|
];
|
|
|
|
for (num_nodes, input_dim, output_dim) in test_cases {
|
|
let graph = create_test_graph(num_nodes, input_dim, 0.15);
|
|
|
|
group.throughput(Throughput::Elements(num_nodes as u64));
|
|
group.bench_function(
|
|
BenchmarkId::new(
|
|
"forward_pass",
|
|
format!("{}x{}->{}", num_nodes, input_dim, output_dim),
|
|
),
|
|
|b| {
|
|
b.iter(|| {
|
|
let mut layer = GCNLayer::new(input_dim, output_dim).unwrap();
|
|
layer.forward(&graph).unwrap()
|
|
});
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_gat_layer(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("gat_layer");
|
|
|
|
let test_cases = vec![
|
|
(10, 4, 8, 2), // small graph, 2 heads
|
|
(25, 6, 12, 4), // medium graph, 4 heads
|
|
(50, 8, 16, 8), // large graph, 8 heads
|
|
];
|
|
|
|
for (num_nodes, input_dim, output_dim, num_heads) in test_cases {
|
|
let graph = create_test_graph(num_nodes, input_dim, 0.2);
|
|
|
|
group.throughput(Throughput::Elements(num_nodes as u64));
|
|
group.bench_function(
|
|
BenchmarkId::new(
|
|
"forward_pass",
|
|
format!("{}x{}->{}_{}h", num_nodes, input_dim, output_dim, num_heads),
|
|
),
|
|
|b| {
|
|
b.iter(|| {
|
|
let mut layer = GATLayer::new(input_dim, output_dim, num_heads).unwrap();
|
|
layer.forward(&graph).unwrap()
|
|
});
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_graphsage_layer(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("graphsage_layer");
|
|
|
|
let test_cases = vec![
|
|
(20, 4, 8, 2), // small graph, sample_size=2
|
|
(50, 8, 16, 5), // medium graph, sample_size=5
|
|
(100, 16, 32, 10), // large graph, sample_size=10
|
|
];
|
|
|
|
for (num_nodes, input_dim, output_dim, sample_size) in test_cases {
|
|
let graph = create_test_graph(num_nodes, input_dim, 0.25);
|
|
|
|
group.throughput(Throughput::Elements(num_nodes as u64));
|
|
group.bench_function(
|
|
BenchmarkId::new(
|
|
"forward_pass",
|
|
format!(
|
|
"{}x{}->{}_s{}",
|
|
num_nodes, input_dim, output_dim, sample_size
|
|
),
|
|
),
|
|
|b| {
|
|
b.iter(|| {
|
|
let mut layer =
|
|
GraphSAGELayer::new(input_dim, output_dim, sample_size).unwrap();
|
|
layer.forward(&graph).unwrap()
|
|
});
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_adjacency_matrix(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("adjacency_matrix");
|
|
|
|
for &size in &[10, 25, 50, 100] {
|
|
let graph = create_test_graph(size, 4, 0.15);
|
|
|
|
group.throughput(Throughput::Elements((size * size) as u64));
|
|
group.bench_with_input(BenchmarkId::new("computation", size), &graph, |b, graph| {
|
|
b.iter(|| graph.adjacency_matrix());
|
|
});
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(
|
|
benches,
|
|
bench_graph_creation,
|
|
bench_message_passing,
|
|
bench_gcn_layer,
|
|
bench_gat_layer,
|
|
bench_graphsage_layer,
|
|
bench_adjacency_matrix
|
|
);
|
|
|
|
criterion_main!(benches);
|