1extern crate kiss_icp_ops as ops;
2
3pub mod deskew;
4pub mod metrics;
5pub mod preprocessing;
6pub mod threshold;
7pub mod types;
8pub mod voxel_hash_map;
9
10pub mod runtime {
11 use std::sync::atomic::{AtomicBool, Ordering};
12
13 use anyhow::Result;
14 use rayon::ThreadPoolBuilder;
15
16 static IS_INITED: AtomicBool = AtomicBool::new(false);
17
18 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
19 pub enum SystemType {
20 #[default]
21 Executable,
22 Library,
23 }
24
25 pub fn init(system_type: SystemType) -> Result<()> {
26 if !IS_INITED.swap(true, Ordering::SeqCst) {
27 let mut builder = ThreadPoolBuilder::new().num_threads(prepare_threads()?);
28 if matches!(system_type, SystemType::Library) {
29 builder = builder.use_current_thread();
30 }
31 builder.build_global()?;
32 }
33 Ok(())
34 }
35
36 #[cfg(not(feature = "numa"))]
37 #[inline]
38 fn prepare_threads() -> Result<usize> {
39 use std::thread;
40
41 const MAX_THREADS: usize = 32;
43
44 Ok(thread::available_parallelism()
45 .map(usize::from)
46 .unwrap_or(1)
47 .min(MAX_THREADS))
48 }
49
50 #[cfg(feature = "numa")]
51 #[inline]
52 fn prepare_threads() -> Result<usize> {
53 let topology = ::hwlocality::Topology::new()?;
55 select_numa_node(&topology)
56 }
57
58 #[cfg(feature = "numa")]
59 #[inline]
60 fn select_numa_node(topology: &::hwlocality::Topology) -> Result<usize> {
61 use hwlocality::cpu::{binding::CpuBindingFlags, cpuset::CpuSet};
62 use rand::{
63 distributions::{Distribution, Uniform},
64 thread_rng,
65 };
66
67 let all_numa_nodes = topology.nodeset();
69 let all_cpus = topology.cpuset();
70
71 let num_numa_nodes = all_numa_nodes
73 .last_set()
74 .map(|set| set.into())
75 .unwrap_or(0usize)
76 + 1;
77 let num_cpus = all_cpus.last_set().map(|set| set.into()).unwrap_or(0usize) + 1;
78 let num_threads_per_cpu = num_cpus / num_numa_nodes;
79
80 let numa_node = Uniform::new(0usize, num_numa_nodes).sample(&mut thread_rng());
82
83 let cpus = {
85 let cpu_begin = numa_node * num_threads_per_cpu;
86 let cpu_end = cpu_begin + num_threads_per_cpu;
87
88 let mut res = CpuSet::new();
89 for idx in cpu_begin..cpu_end {
90 res.set(idx);
91 }
92 res
93 };
94
95 topology.bind_cpu(&cpus, CpuBindingFlags::PROCESS)?;
97
98 Ok(num_threads_per_cpu)
100 }
101}