honeycomb_benches/
grid_gen.rs

1//! Grid generation benchmark
2//!
3//! This benchmark generates a grid using the passed parameters as argument for [`GridDescriptor`]
4//! and [`CMapBuilder`].
5
6use std::time::{Duration, Instant};
7
8use honeycomb::{
9    core::stm::atomically_with_err,
10    prelude::{CMap2, CMapBuilder, CoordsFloat, DartIdType, GridDescriptor, OrbitPolicy},
11};
12use rand::{
13    SeedableRng,
14    distr::{Bernoulli, Distribution},
15    rngs::SmallRng,
16};
17use rayon::prelude::*;
18
19use crate::cli::{Generate2dGridArgs, Split};
20
21pub fn bench_generate_2d_grid<T: CoordsFloat>(args: Generate2dGridArgs) -> CMap2<T> {
22    let descriptor = GridDescriptor::<2, T>::default()
23        .n_cells([args.nx.get(), args.ny.get()])
24        .len_per_cell([T::from(args.lx).unwrap(), T::from(args.ly).unwrap()])
25        .split_cells(args.split.is_some_and(|s| s == Split::Uniform));
26
27    let mut map = CMapBuilder::from_grid_descriptor(descriptor)
28        .build()
29        .unwrap();
30
31    if args.split.is_some_and(|s| s == Split::Random) {
32        // fixed probability and seed value from  the original binary
33        // this can be made into a CL arg if necessary
34        let _ = split_faces_randomly(&mut map, 0.6, 9_817_498_146_784);
35    }
36
37    map
38}
39
40fn split_faces_randomly<T: CoordsFloat>(
41    map: &mut CMap2<T>,
42    p_bernoulli: f64,
43    seed: u64,
44) -> (Duration, Duration) {
45    // sample
46    let mut instant = Instant::now();
47    let faces = map.iter_faces().collect::<Vec<_>>();
48    let n_diag = faces.len();
49    let rng = SmallRng::seed_from_u64(seed);
50    let dist = Bernoulli::new(p_bernoulli).unwrap();
51    let splits: Vec<bool> = dist.sample_iter(rng).take(n_diag).collect();
52    let sample_time = instant.elapsed();
53
54    // build diags
55    instant = Instant::now();
56    let nd = map.allocate_used_darts(n_diag * 2);
57    let nd_range = (nd..nd + (n_diag * 2) as DartIdType).collect::<Vec<_>>();
58    faces
59        .into_iter()
60        .zip(nd_range.chunks(2))
61        .zip(splits)
62        .par_bridge()
63        .for_each(|((df, sl), split)| {
64            let square = df as DartIdType;
65            assert_eq!(map.orbit(OrbitPolicy::FaceLinear, df).count(), 4);
66            let (ddown, dright, dup, dleft) = (square, square + 1, square + 2, square + 3);
67
68            let &[dsplit1, dsplit2] = sl else {
69                unreachable!()
70            };
71            let (dbefore1, dbefore2, dafter1, dafter2) = if split {
72                (ddown, dup, dleft, dright)
73            } else {
74                (dright, dleft, ddown, dup)
75            };
76            let _ = map.force_link::<2>(dsplit1, dsplit2);
77
78            while atomically_with_err(|t| {
79                map.unsew::<1>(t, dbefore1)?;
80                map.unsew::<1>(t, dbefore2)?;
81                map.sew::<1>(t, dsplit1, dafter1)?;
82                map.sew::<1>(t, dsplit2, dafter2)?;
83
84                map.sew::<1>(t, dbefore1, dsplit1)?;
85                map.sew::<1>(t, dbefore2, dsplit2)?;
86                Ok(())
87            })
88            .is_err()
89            {}
90        });
91    (sample_time, instant.elapsed())
92}