honeycomb_benches/
shift.rs

1//! # Description
2//!
3//! ## Routine
4//!
5//! The algorithm fetches all vertices that are not on the border of the map, fetch all identifiers
6//! of each respective vertices' neighbors. Then, for all vertices:
7//!
8//! - compute the average between neighbors
9//! - overwrite current vertex value with computed average
10//!
11//! ## Benchmark
12//!
13//! This binary is meant to be use to evaluate scalability of geometry-only kernels. It is
14//! parallelized using rayon, and the number of thread used for execution can be controlled using
15//! `taskset`. By controlling this, and the grid size, we can evaluate both strong and weak
16//! scaling characteristics.
17
18use rayon::prelude::*;
19
20use honeycomb::core::stm::{Transaction, TransactionControl};
21use honeycomb::prelude::{
22    CMap2, CMapBuilder, CoordsFloat, DartIdType, Orbit2, OrbitPolicy, Vertex2, VertexIdType,
23    NULL_DART_ID,
24};
25
26use crate::cli::ShiftArgs;
27use crate::utils::hash_file;
28
29pub fn bench_shift<T: CoordsFloat>(args: ShiftArgs) -> CMap2<T> {
30    let mut instant = std::time::Instant::now();
31    let input_map = args.input.to_str().unwrap();
32    let input_hash = hash_file(input_map).unwrap();
33    let map: CMap2<T> = CMapBuilder::from(input_map).build().unwrap();
34    let build_time = instant.elapsed();
35
36    if args.no_conflict {
37        todo!("TODO: require a partitioning algorithm")
38    } else {
39        instant = std::time::Instant::now();
40        // fetch all vertices that are not on the boundary of the map
41        let tmp: Vec<(VertexIdType, Vec<VertexIdType>)> = map
42            .iter_vertices()
43            .filter_map(|v| {
44                if Orbit2::new(&map, OrbitPolicy::Vertex, v as DartIdType)
45                    .any(|d| map.beta::<2>(d) == NULL_DART_ID)
46                {
47                    None
48                } else {
49                    Some((
50                        v,
51                        Orbit2::new(&map, OrbitPolicy::Vertex, v as DartIdType)
52                            .map(|d| map.vertex_id(map.beta::<2>(d)))
53                            .collect(),
54                    ))
55                }
56            })
57            .collect();
58        let n_v = tmp.len();
59        let graph_time = instant.elapsed();
60        let n_threads = std::thread::available_parallelism()
61            .map(|v| v.get())
62            .unwrap_or(1);
63
64        println!("| shift benchmark");
65        println!("|-> input      : {input_map} (hash: {input_hash:#0x})");
66        println!("|-> backend    : rayon-iter with {n_threads} thread(s)",);
67        println!("|-> # of rounds: {}", args.n_rounds.get());
68        println!("|-+ init time  :");
69        println!("| |->   map built in {}ms", build_time.as_millis());
70        println!("| |-> graph built in {}ms", graph_time.as_millis());
71
72        println!(" Round | process_time | throughput(vertex/s) | n_transac_retry");
73        // main loop
74        let mut round = 0;
75        let mut process_time;
76        loop {
77            instant = std::time::Instant::now();
78            let n_retry: u32 = tmp
79                .par_iter()
80                .map(|(vid, neigh)| {
81                    let mut n = 0;
82                    Transaction::with_control(
83                        |_| {
84                            n += 1;
85                            TransactionControl::Retry
86                        },
87                        |trans| {
88                            let mut new_val = Vertex2::default();
89                            for v in neigh {
90                                let vertex = map.read_vertex(trans, *v)?.unwrap();
91                                new_val.0 += vertex.0;
92                                new_val.1 += vertex.1;
93                            }
94                            new_val.0 /= T::from(neigh.len()).unwrap();
95                            new_val.1 /= T::from(neigh.len()).unwrap();
96                            map.write_vertex(trans, *vid, new_val)
97                        },
98                    ); // Transaction::with_control
99                    n
100                })
101                .sum();
102            process_time = instant.elapsed().as_secs_f64();
103            println!(
104                " {:>5} | {:>12.6e} | {:>20.6e} | {:>15}",
105                round,
106                process_time,
107                n_v as f64 / process_time,
108                n_retry,
109            );
110
111            round += 1;
112            if round >= args.n_rounds.get() {
113                break;
114            }
115        }
116    }
117
118    map
119}