kiss_icp_core/
lib.rs

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        // heuristic values (Feb 03, 2024)
42        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        // select a NUMA node
54        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        // get NUMA/CPUs info
68        let all_numa_nodes = topology.nodeset();
69        let all_cpus = topology.cpuset();
70
71        // count the resources
72        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        // pick a random NUMA node
81        let numa_node = Uniform::new(0usize, num_numa_nodes).sample(&mut thread_rng());
82
83        // get all the CPUs in the NUMA node
84        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        // bind the process into the NUMA node
96        topology.bind_cpu(&cpus, CpuBindingFlags::PROCESS)?;
97
98        // return the count of available threads
99        Ok(num_threads_per_cpu)
100    }
101}