honeycomb_benches/
utils.rs1use std::collections::hash_map::DefaultHasher;
2use std::fs::File;
3use std::hash::Hasher;
4use std::io::Read;
5
6#[cfg(feature = "bind-threads")]
7use hwlocality::{
8 Topology,
9 cpu::cpuset::CpuSet,
10 object::types::ObjectType,
11 topology::support::{DiscoverySupport, FeatureSupport},
12};
13
14cfg_if::cfg_if! {
15 if #[cfg(feature = "_single_precision")] {
16 pub type FloatType = f32;
20 } else {
21 pub type FloatType = f64;
25 }
26}
27
28pub fn hash_file(path: &str) -> Result<u64, std::io::Error> {
29 let mut file = File::open(path)?;
30 let mut hasher = DefaultHasher::new();
31 let mut buffer = [0; 8192];
32
33 loop {
34 let bytes_read = file.read(&mut buffer)?;
35 if bytes_read == 0 {
36 break;
37 }
38 hasher.write(&buffer[..bytes_read]);
39 }
40
41 Ok(hasher.finish())
42}
43
44pub const NUM_THREADS_VAR: &str = "RAYON_NUM_THREADS";
45
46pub fn get_num_threads() -> Result<usize, String> {
47 match std::env::var(NUM_THREADS_VAR) {
48 Ok(val) => val.parse::<usize>().map_err(|e| e.to_string()),
49 Err(e) => Err(e.to_string()),
50 }
51}
52
53#[cfg(feature = "bind-threads")]
54#[derive(Debug, Default)]
55pub enum BindingPolicy {
56 Disable,
59 Close,
62 #[default]
65 Spread,
66}
67
68#[cfg(feature = "bind-threads")]
72pub const RAYON_PROC_BIND_VAR: &str = "RAYON_PROC_BIND";
73
74#[cfg(feature = "bind-threads")]
75impl BindingPolicy {
76 fn from_env() -> Self {
77 match std::env::var(RAYON_PROC_BIND_VAR) {
78 Ok(val) => match val.to_lowercase().as_str() {
79 "false" => Self::Disable,
80 "close" => Self::Close,
81 "spread" => Self::Spread,
82 "" => Self::default(),
83 _ => {
84 eprintln!("W: unrecognized RAYON_PROC_BIND value (!= false | close | spread)");
85 eprintln!(" continuing with default (spread)");
86 Self::default()
87 }
88 },
89 Err(e) => {
90 match e {
91 std::env::VarError::NotPresent => {}
92 std::env::VarError::NotUnicode(_) => {
93 eprintln!("W: non-unicode RAYON_PROC_BIND value");
94 eprintln!(" continuing with default (spread)");
95 }
96 }
97 Self::default()
98 }
99 }
100 }
101}
102
103#[cfg(feature = "bind-threads")]
104pub fn check_hwloc_support(topology: &Topology) -> Result<(), String> {
105 if !topology.supports(FeatureSupport::discovery, DiscoverySupport::pu_count) {
106 return Err("missing PU reporting support".to_string());
107 }
108 if !topology
109 .feature_support()
110 .cpu_binding()
111 .is_some_and(|s| s.get_thread() && s.set_thread())
112 {
113 return Err("missing binding support".to_string());
114 }
115
116 Ok(())
117}
118
119#[cfg(feature = "bind-threads")]
126pub fn get_proc_list(topology: &Topology) -> Option<Vec<CpuSet>> {
127 let binding_policy = BindingPolicy::from_env();
128 let core_depth = topology
129 .depth_or_below_for_type(ObjectType::Core)
130 .expect("E: unreachable");
131
132 match binding_policy {
133 BindingPolicy::Disable => None,
134 BindingPolicy::Close => {
135 let mut pu_set = Vec::with_capacity(256);
136 topology.objects_at_depth(core_depth).for_each(|c| {
137 let target = c.cpuset().unwrap().clone_target();
138 let w = target.weight();
139 if !(w == Some(1) || w == Some(2)) {
140 panic!()
141 }
142 target
143 .iter_set()
144 .map(CpuSet::from)
145 .for_each(|t| pu_set.push(t));
146 });
147 Some(pu_set)
148 }
149 BindingPolicy::Spread => {
150 let mut first_pu_set = Vec::with_capacity(128);
151 let mut second_pu_set = Vec::with_capacity(128);
152 topology.objects_at_depth(core_depth).for_each(|c| {
153 let target = c.cpuset().expect("E: unreachable").clone_target();
154 match target.weight() {
156 Some(1) => {
157 first_pu_set.push(target);
159 }
160 Some(2) => {
161 let [first_pu, second_pu]: [CpuSet; 2] = target
163 .iter_set()
164 .map(CpuSet::from)
165 .collect::<Vec<_>>()
166 .try_into()
167 .expect("E: unreachable");
168 first_pu_set.push(first_pu);
169 second_pu_set.push(second_pu);
170 }
171 Some(_) | None => {
172 panic!("E: architecture too cursed")
173 }
174 }
175 });
176 first_pu_set.append(&mut second_pu_set);
177 Some(first_pu_set)
178 }
179 }
180}
181
182#[cfg(feature = "profiling")]
183pub static mut PERF_FIFO: Option<File> = None;
184
185#[macro_export]
189macro_rules! prof_init {
190 () => {
191 #[cfg(feature = "profiling")]
192 {
193 unsafe {
194 $crate::utils::PERF_FIFO = Some(
195 std::fs::OpenOptions::new()
196 .write(true)
197 .open("/tmp/hc_perf_control")
198 .expect("Failed to open FIFO"),
199 );
200 }
201 }
202 };
203}
204
205#[macro_export]
209macro_rules! prof_start {
210 ($var: literal) => {
211 #[cfg(feature = "profiling")]
212 {
213 if std::env::var_os($var).is_some() {
215 use std::io::Write;
216 unsafe {
217 if let Some(ref mut f) = $crate::utils::PERF_FIFO {
218 f.write_all(b"enable\n")
219 .expect("E: failed to write to FIFO");
220 f.flush().expect("E: failed to flush FIFO");
221 }
222 }
223 }
224 }
225 };
226}
227
228#[macro_export]
232macro_rules! prof_stop {
233 ($var: literal) => {
234 #[cfg(feature = "profiling")]
235 {
236 if std::env::var_os($var).is_some() {
238 use std::io::Write;
239 unsafe {
240 if let Some(ref mut f) = $crate::utils::PERF_FIFO {
241 f.write_all(b"disable\n")
242 .expect("E: failed to write to FIFO");
243 f.flush().expect("E: failed to flush FIFO");
244 }
245 }
246 }
247 }
248 };
249}