diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index feffb49f24..2ea0bf9890 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -41,7 +41,7 @@ jobs: - name: Run benchmark (Unix) run: | set -o pipefail - cargo bench --bench base --bench algobench -p raphtory-benchmark -- --output-format=bencher | tee benchmark-result.txt + cargo bench --bench base --bench algobench_fast --bench algobench_medium --bench algobench_slow -p raphtory-benchmark -- --output-format=bencher | tee benchmark-result.txt - name: Restore Cargo.lock to avoid dirty working tree run: git checkout -- Cargo.lock - name: Store benchmark results from master branch diff --git a/raphtory-benchmark/Cargo.toml b/raphtory-benchmark/Cargo.toml index ee49fdfd44..1636ac676e 100644 --- a/raphtory-benchmark/Cargo.toml +++ b/raphtory-benchmark/Cargo.toml @@ -44,7 +44,15 @@ name = "graph_ops" harness = false [[bench]] -name = "algobench" +name = "algobench_fast" +harness = false + +[[bench]] +name = "algobench_medium" +harness = false + +[[bench]] +name = "algobench_slow" harness = false [[bench]] diff --git a/raphtory-benchmark/benches/algobench.rs b/raphtory-benchmark/benches/algobench.rs deleted file mode 100644 index 8fab04fdd2..0000000000 --- a/raphtory-benchmark/benches/algobench.rs +++ /dev/null @@ -1,143 +0,0 @@ -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, SamplingMode}; -use raphtory::{ - algorithms::{ - centrality::pagerank::page_rank, - components::weakly_connected_components, - metrics::clustering_coefficient::{ - global_clustering_coefficient::global_clustering_coefficient, - local_clustering_coefficient::local_clustering_coefficient, - }, - motifs::{ - global_temporal_three_node_motifs::global_temporal_three_node_motif, - local_triangle_count::local_triangle_count, - }, - }, - graphgen::random_attachment::random_attachment, - prelude::*, -}; -use raphtory_benchmark::common::bench; -use rayon::prelude::*; -use std::hint::black_box; - -pub fn local_triangle_count_analysis(c: &mut Criterion) { - let mut group = c.benchmark_group("local_triangle_count"); - group.sample_size(10); - bench(&mut group, "local_triangle_count", None, |b| { - let g = raphtory::graph_loader::lotr_graph::lotr_graph(); - let windowed_graph = g.window(i64::MIN, i64::MAX); - - b.iter(|| { - let node_ids = windowed_graph.nodes().id().collect::>(); - - node_ids.into_par_iter().for_each(|v| { - local_triangle_count(&windowed_graph, v).unwrap(); - }); - }) - }); - - group.finish(); -} - -pub fn local_clustering_coefficient_analysis(c: &mut Criterion) { - let mut group = c.benchmark_group("local_clustering_coefficient"); - - bench(&mut group, "local_clustering_coefficient", None, |b| { - let g: Graph = raphtory::graph_loader::lotr_graph::lotr_graph(); - - b.iter(|| local_clustering_coefficient(&g, "Gandalf")) - }); - - group.finish(); -} - -pub fn graphgen_large_clustering_coeff(c: &mut Criterion) { - let mut group = c.benchmark_group("graphgen_large_clustering_coeff"); - // generate graph - let graph = Graph::new(); - let seed: [u8; 32] = [1; 32]; - random_attachment(&graph, 500000, 4, Some(seed)); - - group.sampling_mode(SamplingMode::Flat); - group.measurement_time(std::time::Duration::from_secs(60)); - group.sample_size(10); - group.bench_with_input( - BenchmarkId::new("graphgen_large_clustering_coeff", &graph), - &graph, - |b, graph| { - b.iter(|| { - let result = global_clustering_coefficient(graph); - black_box(result); - }); - }, - ); - group.finish() -} - -pub fn graphgen_large_pagerank(c: &mut Criterion) { - let mut group = c.benchmark_group("graphgen_large_pagerank"); - // generate graph - let graph = Graph::new(); - let seed: [u8; 32] = [1; 32]; - random_attachment(&graph, 500000, 4, Some(seed)); - - group.sampling_mode(SamplingMode::Flat); - group.measurement_time(std::time::Duration::from_secs(20)); - group.sample_size(10); - group.bench_with_input( - BenchmarkId::new("graphgen_large_pagerank", &graph), - &graph, - |b, graph| { - b.iter(|| { - let result = page_rank(graph, None, Some(100), None, None, true, None); - black_box(result); - }); - }, - ); - group.finish() -} - -pub fn graphgen_large_concomp(c: &mut Criterion) { - let mut group = c.benchmark_group("graphgen_large_concomp"); - // generate graph - let graph = Graph::new(); - let seed: [u8; 32] = [1; 32]; - random_attachment(&graph, 500000, 4, Some(seed)); - - group.sampling_mode(SamplingMode::Flat); - group.measurement_time(std::time::Duration::from_secs(60)); - group.sample_size(10); - group.bench_with_input( - BenchmarkId::new("graphgen_large_concomp", &graph), - &graph, - |b, graph| { - b.iter(|| { - let result = weakly_connected_components(graph); - black_box(result); - }); - }, - ); - group.finish() -} - -pub fn temporal_motifs(c: &mut Criterion) { - let mut group = c.benchmark_group("temporal_motifs"); - - bench(&mut group, "temporal_motifs", None, |b| { - let g: Graph = raphtory::graph_loader::lotr_graph::lotr_graph(); - - b.iter(|| global_temporal_three_node_motif(&g, 100, None)) - }); - - group.finish(); -} - -criterion_group!( - benches, - local_triangle_count_analysis, - local_clustering_coefficient_analysis, - graphgen_large_clustering_coeff, - graphgen_large_pagerank, - graphgen_large_concomp, - temporal_motifs, -); -criterion_main!(benches); diff --git a/raphtory-benchmark/benches/algobench_fast.rs b/raphtory-benchmark/benches/algobench_fast.rs new file mode 100644 index 0000000000..dd63b2ace8 --- /dev/null +++ b/raphtory-benchmark/benches/algobench_fast.rs @@ -0,0 +1,278 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use rand::{rngs::SmallRng, SeedableRng}; +use raphtory::{ + algorithms::{ + centrality::degree_centrality::degree_centrality, + components::weakly_connected_components, + components::{out_component, out_component_filtered}, + dynamics::temporal::epidemics::{temporal_SEIR, Number}, + metrics::{ + clustering_coefficient::{ + local_clustering_coefficient::local_clustering_coefficient, + local_clustering_coefficient_batch::local_clustering_coefficient_batch, + }, + degree::{ + average_degree, max_degree, max_in_degree, max_out_degree, min_degree, + min_in_degree, min_out_degree, + }, + directed_graph_density::directed_graph_density, + }, + motifs::local_triangle_count::local_triangle_count, + pathing::temporal_reachability::temporally_reachable_nodes, + }, + db::graph::views::filter::Unfiltered, + prelude::*, +}; +use raphtory_benchmark::algobench_common::{ + first_node_id, graph_benchmark, graph_benchmark_with_setup, large_random_attachment_filtered, + large_random_attachment_graph, large_random_attachment_layered, + large_random_attachment_subgraph, +}; + +pub fn local_triangle_count_analysis(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "local_triangle_count", + 5, + 10, + large_random_attachment_graph, + first_node_id, + |graph, node_id| local_triangle_count(graph, node_id.clone()).unwrap(), + ); +} + +pub fn local_clustering_coefficient_analysis(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "local_clustering_coefficient", + 5, + 10, + large_random_attachment_graph, + first_node_id, + |graph, node_id| local_clustering_coefficient(graph, node_id.clone()), + ); +} + +pub fn graphgen_directed_density(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_directed_density", + 5, + 10, + large_random_attachment_graph, + |graph, _| directed_graph_density(graph), + ); + graph_benchmark( + c, + "graphgen_directed_density_subgraph", + 5, + 10, + large_random_attachment_subgraph, + |graph, _| directed_graph_density(graph), + ); + graph_benchmark( + c, + "graphgen_directed_density_layered", + 5, + 10, + large_random_attachment_layered, + |graph, _| directed_graph_density(graph), + ); + graph_benchmark( + c, + "graphgen_directed_density_graph_filtered", + 5, + 10, + large_random_attachment_filtered, + |graph, _| directed_graph_density(graph), + ) +} + +pub fn graphgen_degree_centrality(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_degree_centrality", + 5, + 10, + large_random_attachment_graph, + |graph, _| degree_centrality(graph), + ); +} + +pub fn graphgen_concomp(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_concomp", + 5, + 10, + large_random_attachment_graph, + |graph, _| weakly_connected_components(graph), + ); +} + +pub fn graphgen_max_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_max_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| max_degree(graph), + ); +} + +pub fn graphgen_min_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_min_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| min_degree(graph), + ); +} + +pub fn graphgen_max_out_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_max_out_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| max_out_degree(graph), + ); +} + +pub fn graphgen_max_in_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_max_in_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| max_in_degree(graph), + ); +} + +pub fn graphgen_min_out_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_min_out_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| min_out_degree(graph), + ); +} + +pub fn graphgen_min_in_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_min_in_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| min_in_degree(graph), + ); +} + +pub fn graphgen_average_degree(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_average_degree", + 5, + 10, + large_random_attachment_graph, + |graph, _| average_degree(graph), + ); +} + +pub fn graphgen_local_clustering_coefficient_batch(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_local_clustering_coefficient_batch", + 5, + 10, + large_random_attachment_graph, + first_node_id, + |graph, node_id| local_clustering_coefficient_batch(graph, vec![node_id.clone()]), + ); +} + +pub fn graphgen_temporally_reachable_nodes(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_temporally_reachable_nodes", + 5, + 10, + large_random_attachment_graph, + first_node_id, + |graph, source| temporally_reachable_nodes(graph, None, 20, 0, vec![source.clone()], None), + ); +} + +pub fn graphgen_out_component(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_out_component", + 5, + 10, + large_random_attachment_graph, + first_node_id, + |graph, source| { + let node = graph.node(source.clone()).expect("source node exists"); + out_component(node) + }, + ); +} + +pub fn graphgen_out_component_filtered(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_out_component_filtered", + 5, + 10, + large_random_attachment_graph, + first_node_id, + |graph, source| { + let node = graph.node(source.clone()).expect("source node exists"); + out_component_filtered(node, Unfiltered).unwrap() + }, + ); +} + +pub fn graphgen_temporal_seir(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_temporal_seir", + 5, + 10, + large_random_attachment_graph, + |graph, _| { + let mut rng = SmallRng::seed_from_u64(1); + temporal_SEIR(graph, Some(0.1), None, 0.5f64, 0, Number(1), &mut rng).unwrap() + }, + ); +} + +criterion_group!( + benches, + local_triangle_count_analysis, + local_clustering_coefficient_analysis, + graphgen_directed_density, + graphgen_degree_centrality, + graphgen_concomp, + graphgen_max_degree, + graphgen_min_degree, + graphgen_max_out_degree, + graphgen_max_in_degree, + graphgen_min_out_degree, + graphgen_min_in_degree, + graphgen_average_degree, + graphgen_local_clustering_coefficient_batch, + graphgen_temporally_reachable_nodes, + graphgen_out_component, + graphgen_out_component_filtered, + graphgen_temporal_seir, +); +criterion_main!(benches); diff --git a/raphtory-benchmark/benches/algobench_medium.rs b/raphtory-benchmark/benches/algobench_medium.rs new file mode 100644 index 0000000000..b66172b18d --- /dev/null +++ b/raphtory-benchmark/benches/algobench_medium.rs @@ -0,0 +1,379 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use raphtory::{ + algorithms::{ + centrality::{hits::hits, pagerank::page_rank}, + community_detection::{ + label_propagation::label_propagation, louvain::louvain, modularity::ModularityUnDir, + }, + components::{in_component, in_component_filtered, strongly_connected_components}, + cores::k_core::{k_core, k_core_set}, + embeddings::fast_rp::fast_rp, + metrics::{ + balance::balance, + clustering_coefficient::global_clustering_coefficient::global_clustering_coefficient, + reciprocity::{all_local_reciprocity, global_reciprocity}, + }, + motifs::{ + global_temporal_three_node_motifs::{ + global_temporal_three_node_motif, temporal_three_node_motif_multi, + triangle_motifs as global_triangle_motifs_internal, + }, + local_temporal_three_node_motifs::{ + temporal_three_node_motif as local_temporal_three_node_motif, + triangle_motifs as local_triangle_motifs_internal, + }, + triangle_count::triangle_count, + triplet_count::triplet_count, + }, + pathing::{ + dijkstra::dijkstra_single_source_shortest_paths, + single_source_shortest_path::single_source_shortest_path, + }, + projections::temporal_bipartite_projection::temporal_bipartite_projection, + }, + db::graph::views::filter::Unfiltered, + prelude::*, +}; +use raphtory_api::core::Direction; +use raphtory_benchmark::algobench_common::{ + first_node_id, graph_benchmark, graph_benchmark_with_setup, medium_random_attachment_filtered, + medium_random_attachment_graph, medium_random_attachment_layered, + medium_random_attachment_subgraph, medium_typed_random_attachment_graph, + medium_weighted_random_attachment_graph, +}; + +pub fn graphgen_clustering_coeff(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_clustering_coeff", + 5, + 10, + medium_random_attachment_graph, + |graph, _| global_clustering_coefficient(graph), + ); +} + +pub fn graphgen_pagerank(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_pagerank", + 5, + 10, + medium_random_attachment_graph, + |graph, _| page_rank(graph, None, Some(100), None, None, true, None), + ); + graph_benchmark( + c, + "graphgen_pagerank_subgraph", + 5, + 10, + medium_random_attachment_subgraph, + |graph, _| page_rank(graph, None, Some(100), None, None, true, None), + ); + graph_benchmark( + c, + "graphgen_pagerank_layered", + 5, + 10, + medium_random_attachment_layered, + |graph, _| page_rank(graph, None, Some(100), None, None, true, None), + ); + graph_benchmark( + c, + "graphgen_pagerank_graph_filtered", + 5, + 10, + medium_random_attachment_filtered, + |graph, _| page_rank(graph, None, Some(100), None, None, true, None), + ) +} + +pub fn graphgen_hits(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_hits", + 5, + 10, + medium_random_attachment_graph, + |graph, _| hits(graph, 100, None), + ); +} + +pub fn graphgen_triangle_count(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_triangle_count", + 5, + 10, + medium_random_attachment_graph, + |graph, _| triangle_count(graph, None), + ); +} + +pub fn graphgen_triplet_count(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_triplet_count", + 5, + 10, + medium_random_attachment_graph, + |graph, _| triplet_count(graph, None), + ); +} + +pub fn graphgen_reciprocity(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_reciprocity", + 5, + 10, + medium_random_attachment_graph, + |graph, _| global_reciprocity(graph), + ); +} + +pub fn graphgen_scc(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_scc", + 5, + 10, + medium_random_attachment_graph, + |graph, _| strongly_connected_components(graph), + ); +} + +pub fn graphgen_label_propagation(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_label_propagation", + 5, + 10, + medium_random_attachment_graph, + |graph, _| label_propagation(graph, 20, Some([1; 32]), None), + ); +} + +pub fn graphgen_louvain(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_louvain", + 5, + 10, + medium_random_attachment_graph, + |graph, _| louvain::(graph, 1.0, None, None, Some(42)), + ); +} + +pub fn graphgen_all_local_reciprocity(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_all_local_reciprocity", + 5, + 10, + medium_random_attachment_graph, + |graph, _| all_local_reciprocity(graph), + ); +} + +pub fn graphgen_balance(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_balance", + 5, + 10, + medium_weighted_random_attachment_graph, + |graph, _| balance(graph, "weight".to_string(), Direction::BOTH).unwrap(), + ); +} + +pub fn graphgen_temporal_motif_multi(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_temporal_motif_multi", + 5, + 10, + medium_random_attachment_graph, + |graph, _| temporal_three_node_motif_multi(graph, vec![100], None), + ); +} + +pub fn graphgen_local_temporal_motif(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_local_temporal_motif", + 5, + 10, + medium_random_attachment_graph, + |graph, _| local_temporal_three_node_motif(graph, 100, None), + ); +} + +pub fn graphgen_dijkstra(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_dijkstra", + 5, + 10, + medium_random_attachment_graph, + first_node_id, + |graph, source| { + dijkstra_single_source_shortest_paths( + graph, + source.clone(), + vec![source.clone()], + None, + Direction::BOTH, + ) + .unwrap() + }, + ); +} + +pub fn graphgen_single_source_shortest_path(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_single_source_shortest_path", + 5, + 10, + medium_random_attachment_graph, + first_node_id, + |graph, source| single_source_shortest_path(graph, source.clone(), None), + ); +} + +pub fn graphgen_in_component(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_in_component", + 5, + 10, + medium_random_attachment_graph, + first_node_id, + |graph, source| { + let node = graph.node(source.clone()).expect("source node exists"); + in_component(node) + }, + ); +} + +pub fn graphgen_in_component_filtered(c: &mut Criterion) { + graph_benchmark_with_setup( + c, + "graphgen_in_component_filtered", + 5, + 10, + medium_random_attachment_graph, + first_node_id, + |graph, source| { + let node = graph.node(source.clone()).expect("source node exists"); + in_component_filtered(node, Unfiltered).unwrap() + }, + ); +} + +pub fn graphgen_internal_global_triangle_motifs(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_internal_global_triangle_motifs", + 5, + 10, + medium_random_attachment_graph, + |graph, _| global_triangle_motifs_internal(graph, vec![100], None), + ); +} + +pub fn graphgen_internal_local_triangle_motifs(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_internal_local_triangle_motifs", + 5, + 10, + medium_random_attachment_graph, + |graph, _| local_triangle_motifs_internal(graph, vec![100], None), + ); +} + +pub fn graphgen_k_core_set(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_k_core_set", + 5, + 10, + medium_random_attachment_graph, + |graph, _| k_core_set(graph, 2, usize::MAX, None), + ); +} + +pub fn graphgen_k_core(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_k_core", + 5, + 10, + medium_random_attachment_graph, + |graph, _| k_core(graph, 2, usize::MAX, None), + ); +} + +pub fn graphgen_fast_rp(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_fast_rp", + 5, + 10, + medium_random_attachment_graph, + |graph, _| fast_rp(graph, 32, 0.5, vec![1.0, 1.0, 1.0], Some(1), None), + ); +} + +pub fn graphgen_temporal_bipartite_projection(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_temporal_bipartite_projection", + 5, + 10, + medium_typed_random_attachment_graph, + |graph, _| temporal_bipartite_projection(graph, 1, "Right".to_string()), + ); +} + +pub fn temporal_motifs(c: &mut Criterion) { + graph_benchmark( + c, + "temporal_motifs", + 5, + 10, + medium_random_attachment_graph, + |graph, _| global_temporal_three_node_motif(graph, 100, None), + ); +} + +criterion_group!( + benches, + graphgen_clustering_coeff, + graphgen_pagerank, + graphgen_hits, + graphgen_triangle_count, + graphgen_triplet_count, + graphgen_reciprocity, + graphgen_scc, + graphgen_label_propagation, + graphgen_louvain, + graphgen_all_local_reciprocity, + graphgen_balance, + graphgen_temporal_motif_multi, + graphgen_local_temporal_motif, + graphgen_dijkstra, + graphgen_single_source_shortest_path, + graphgen_in_component, + graphgen_in_component_filtered, + graphgen_internal_global_triangle_motifs, + graphgen_internal_local_triangle_motifs, + graphgen_k_core_set, + graphgen_k_core, + graphgen_fast_rp, + graphgen_temporal_bipartite_projection, + temporal_motifs, +); +criterion_main!(benches); diff --git a/raphtory-benchmark/benches/algobench_slow.rs b/raphtory-benchmark/benches/algobench_slow.rs new file mode 100644 index 0000000000..4f17ad1d5d --- /dev/null +++ b/raphtory-benchmark/benches/algobench_slow.rs @@ -0,0 +1,161 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use raphtory::{ + algorithms::{ + bipartite::max_weight_matching::max_weight_matching, + centrality::betweenness::betweenness_centrality, + components::{ + in_components, in_components_filtered, out_components, out_components_filtered, + }, + layout::{ + cohesive_fruchterman_reingold::cohesive_fruchterman_reingold, + fruchterman_reingold::fruchterman_reingold_unbounded, + }, + motifs::temporal_rich_club_coefficient::temporal_rich_club_coefficient, + }, + db::graph::views::filter::Unfiltered, + prelude::*, +}; +use raphtory_benchmark::algobench_common::{ + graph_benchmark, tiny_random_attachment_filtered, tiny_random_attachment_graph, + tiny_random_attachment_layered, tiny_random_attachment_subgraph, +}; + +pub fn graphgen_betweenness(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_betweenness", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| betweenness_centrality(graph, None, false), + ); + graph_benchmark( + c, + "graphgen_betweenness_subgraph", + 5, + 10, + tiny_random_attachment_subgraph, + |graph, _| betweenness_centrality(graph, None, false), + ); + graph_benchmark( + c, + "graphgen_betweenness_layered", + 5, + 10, + tiny_random_attachment_layered, + |graph, _| betweenness_centrality(graph, None, false), + ); + graph_benchmark( + c, + "graphgen_betweenness_graph_filtered", + 5, + 10, + tiny_random_attachment_filtered, + |graph, _| betweenness_centrality(graph, None, false), + ) +} + +pub fn graphgen_in_components(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_in_components", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| in_components(graph, None), + ); +} + +pub fn graphgen_out_components(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_out_components", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| out_components(graph, None), + ); +} + +pub fn graphgen_in_components_filtered(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_in_components_filtered", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| in_components_filtered(graph, None, Unfiltered).unwrap(), + ); +} + +pub fn graphgen_out_components_filtered(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_out_components_filtered", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| out_components_filtered(graph, None, Unfiltered).unwrap(), + ); +} + +pub fn graphgen_temporal_rich_club(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_temporal_rich_club", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| { + let rolling = graph.rolling(1, Some(1)).unwrap(); + temporal_rich_club_coefficient(graph, rolling, 3, 3) + }, + ); +} + +pub fn graphgen_fruchterman_reingold(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_fruchterman_reingold", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| fruchterman_reingold_unbounded(graph, 5, 1.0, 1.0, 0.9, 0.1), + ); +} + +pub fn graphgen_cohesive_fruchterman_reingold(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_cohesive_fruchterman_reingold", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| cohesive_fruchterman_reingold(graph, 5, 1.0, 1.0, 0.9, 0.1), + ); +} + +pub fn graphgen_max_weight_matching(c: &mut Criterion) { + graph_benchmark( + c, + "graphgen_max_weight_matching", + 5, + 10, + tiny_random_attachment_graph, + |graph, _| max_weight_matching(graph, None, false, false), + ); +} + +criterion_group!( + benches, + graphgen_betweenness, + graphgen_in_components, + graphgen_out_components, + graphgen_in_components_filtered, + graphgen_out_components_filtered, + graphgen_temporal_rich_club, + graphgen_fruchterman_reingold, + graphgen_cohesive_fruchterman_reingold, + graphgen_max_weight_matching, +); +criterion_main!(benches); diff --git a/raphtory-benchmark/src/algobench_common.rs b/raphtory-benchmark/src/algobench_common.rs new file mode 100644 index 0000000000..f0b782952a --- /dev/null +++ b/raphtory-benchmark/src/algobench_common.rs @@ -0,0 +1,243 @@ +use criterion::{Criterion, SamplingMode}; +use raphtory::{ + db::{ + api::view::{Filter, StaticGraphViewOps}, + graph::views::{ + filter::model::{ + degree_filter::DegreeFilterFactory, property_filter::ops::PropertyFilterOps, + }, + node_subgraph::NodeSubgraph, + }, + }, + graphgen::random_attachment::random_attachment, + prelude::*, +}; +use std::sync::OnceLock; + +pub fn graph_benchmark_with_setup( + c: &mut Criterion, + name: &str, + measurement_secs: u64, + sample_size: usize, + build_graph: BuildGraph, + setup: Setup, + mut run: Run, +) where + G: StaticGraphViewOps, + BuildGraph: FnOnce() -> G, + Setup: Fn(&G) -> SetupData, + Run: FnMut(&G, &SetupData) -> Output, +{ + let mut group = c.benchmark_group(name); + let graph = build_graph(); + let setup_data = setup(&graph); + + group.sampling_mode(SamplingMode::Flat); + group.measurement_time(std::time::Duration::from_secs(measurement_secs)); + group.sample_size(sample_size); + group.bench_function(name, |b| { + b.iter(|| { + run(&graph, &setup_data); + }); + }); + group.finish(); +} + +pub fn graph_benchmark( + c: &mut Criterion, + name: &str, + measurement_secs: u64, + sample_size: usize, + build_graph: BuildGraph, + run: Run, +) where + G: StaticGraphViewOps, + BuildGraph: FnOnce() -> G, + Run: FnMut(&G, &()) -> Output, +{ + graph_benchmark_with_setup( + c, + name, + measurement_secs, + sample_size, + build_graph, + |_| (), + run, + ) +} + +pub fn first_node_id(graph: &G) -> GID { + graph + .nodes() + .id() + .iter_values() + .next() + .expect("graph has nodes") +} + +// graph constructors + +pub fn build_large_random_attachment_graph() -> Graph { + let graph = Graph::new(); + let seed: [u8; 32] = [1; 32]; + random_attachment(&graph, 5000, 4, Some(seed)); + graph +} + +pub fn large_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_large_random_attachment_graph) + .clone() +} + +pub fn large_random_attachment_subgraph() -> NodeSubgraph { + let graph = large_random_attachment_graph(); + let subgraph = graph.subgraph(graph.nodes()); + subgraph +} + +pub fn large_random_attachment_filtered() -> impl StaticGraphViewOps { + large_random_attachment_graph() + .filter(NodeFilter.degree().ge(1u64)) + .unwrap() +} + +pub fn large_random_attachment_layered() -> impl StaticGraphViewOps { + let graph = large_random_attachment_graph(); + graph.default_layer() +} + +pub fn build_large_weighted_random_attachment_graph() -> Graph { + let graph = build_large_random_attachment_graph(); + let ids = graph.nodes().id().iter_values().collect::>(); + if let (Some(src), Some(dst)) = (ids.first(), ids.get(1)) { + graph + .add_edge(0, src.clone(), dst.clone(), [("weight", 1.0f64)], None) + .expect("unable to add weighted edge"); + } + graph +} + +pub fn large_weighted_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_large_weighted_random_attachment_graph) + .clone() +} + +pub fn build_large_typed_random_attachment_graph() -> Graph { + let graph = build_large_random_attachment_graph(); + let ids = graph.nodes().id().iter_values().collect::>(); + for id in ids { + graph + .add_node(0, id, NO_PROPS, Some("Right"), None) + .expect("unable to set node type"); + } + graph +} + +pub fn large_typed_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_large_typed_random_attachment_graph) + .clone() +} + +pub fn build_medium_random_attachment_graph() -> Graph { + let graph = Graph::new(); + let seed: [u8; 32] = [1; 32]; + random_attachment(&graph, 1500, 4, Some(seed)); + graph +} + +pub fn medium_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_medium_random_attachment_graph) + .clone() +} + +pub fn medium_random_attachment_subgraph() -> NodeSubgraph { + let graph = medium_random_attachment_graph(); + let subgraph = graph.subgraph(graph.nodes()); + subgraph +} + +pub fn medium_random_attachment_filtered() -> impl StaticGraphViewOps { + medium_random_attachment_graph() + .filter(NodeFilter.degree().ge(0u64)) + .unwrap() +} + +pub fn medium_random_attachment_layered() -> impl StaticGraphViewOps { + let graph = medium_random_attachment_graph(); + graph.default_layer() +} + +pub fn build_medium_weighted_random_attachment_graph() -> Graph { + let graph = build_medium_random_attachment_graph(); + let ids = graph.nodes().id().iter_values().collect::>(); + if let (Some(src), Some(dst)) = (ids.first(), ids.get(1)) { + graph + .add_edge(0, src.clone(), dst.clone(), [("weight", 1.0f64)], None) + .expect("unable to add weighted edge"); + } + graph +} + +pub fn medium_weighted_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_medium_weighted_random_attachment_graph) + .clone() +} + +pub fn build_medium_typed_random_attachment_graph() -> Graph { + let graph = build_medium_random_attachment_graph(); + let ids = graph.nodes().id().iter_values().collect::>(); + for id in ids { + graph + .add_node(0, id, NO_PROPS, Some("Right"), None) + .expect("unable to set node type"); + } + graph +} + +pub fn medium_typed_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_medium_typed_random_attachment_graph) + .clone() +} + +pub fn build_tiny_random_attachment_graph() -> Graph { + let graph = Graph::new(); + let seed: [u8; 32] = [1; 32]; + random_attachment(&graph, 100, 4, Some(seed)); + graph +} + +pub fn tiny_random_attachment_graph() -> Graph { + static GRAPH: OnceLock = OnceLock::new(); + GRAPH + .get_or_init(build_tiny_random_attachment_graph) + .clone() +} + +pub fn tiny_random_attachment_subgraph() -> NodeSubgraph { + let graph = tiny_random_attachment_graph(); + let subgraph = graph.subgraph(graph.nodes()); + subgraph +} + +pub fn tiny_random_attachment_filtered() -> impl StaticGraphViewOps { + tiny_random_attachment_graph() + .filter(NodeFilter.degree().ge(0u64)) + .unwrap() +} + +pub fn tiny_random_attachment_layered() -> impl StaticGraphViewOps { + let graph = tiny_random_attachment_graph(); + graph.default_layer() +} diff --git a/raphtory-benchmark/src/lib.rs b/raphtory-benchmark/src/lib.rs index 14d1c1908e..269055d068 100644 --- a/raphtory-benchmark/src/lib.rs +++ b/raphtory-benchmark/src/lib.rs @@ -1,2 +1,3 @@ +pub mod algobench_common; pub mod common; pub mod graph_gen;