crater/utils.rs
1#![allow(non_camel_case_types)]
2
3use std::time::{Duration, SystemTime};
4
5/// Times the execution of a closure and returns both the result and elapsed duration.
6///
7/// This utility function is essential for performance analysis in safety-critical applications
8/// where timing characteristics must be precisely measured and validated.
9///
10/// # Parameters
11///
12/// * `f` - Closure to execute and time
13///
14/// # Returns
15///
16/// A tuple containing:
17/// - The closure's return value
18/// - [`Duration`] representing the elapsed execution time
19///
20/// # Examples
21///
22/// ```rust
23/// use crater::utils::timeit;
24/// use std::thread;
25/// use std::time::Duration;
26///
27/// // Time a simple computation
28/// let (result, duration) = timeit(|| {
29/// (1..1000).sum::<i32>()
30/// });
31///
32/// println!("Sum: {}, computed in {:?}", result, duration);
33/// ```
34///
35/// ```rust
36/// use crater::csg::prelude::*;
37/// use crater::primitives::prelude::*;
38/// use crater::utils::timeit;
39/// use burn::prelude::*;
40/// use burn::backend::ndarray::NdArrayDevice;
41///
42/// // Time mesh generation for performance analysis
43/// let (mesh, generation_time) = timeit(|| {
44/// let sphere = Field3D::<burn::backend::ndarray::NdArray>::sphere(1.0, NdArrayDevice::Cpu).into_isosurface(0.0);
45/// let region = Region::HalfSpace(sphere, Side::Negative);
46///
47/// let params = MarchingCubesParams {
48/// region,
49/// bounds: BoundingBox::new([-2.0, -2.0, -2.0], [2.0, 2.0, 2.0]),
50/// resolution: (64, 64, 64),
51/// algebra: Algebra::default(),
52/// };
53///
54/// marching_cubes(¶ms, &NdArrayDevice::Cpu)
55/// });
56///
57/// println!("Generated {} triangles in {:?}",
58/// mesh.triangles.len(), generation_time);
59/// ```
60pub fn timeit<F: Fn() -> T, T>(f: F) -> (T, Duration) {
61 let start = SystemTime::now();
62 let result = f();
63 let end = SystemTime::now();
64 let duration = end.duration_since(start).unwrap();
65 (result, duration)
66}
67
68/// See the brilliant rayon blog post. Credits to \[6\] for this implementation.
69pub trait Joiner {
70 fn is_parallel() -> bool;
71 fn join<A, R_A, B, R_B>(oper_a: A, oper_b: B) -> (R_A, R_B)
72 where
73 A: FnOnce() -> R_A + Send,
74 B: FnOnce() -> R_B + Send,
75 R_A: Send,
76 R_B: Send;
77}
78
79pub struct Parallel;
80impl Joiner for Parallel {
81 #[inline]
82 fn is_parallel() -> bool {
83 true
84 }
85 #[inline]
86 fn join<A, R_A, B, R_B>(oper_a: A, oper_b: B) -> (R_A, R_B)
87 where
88 A: FnOnce() -> R_A + Send,
89 B: FnOnce() -> R_B + Send,
90 R_A: Send,
91 R_B: Send,
92 {
93 rayon::join(oper_a, oper_b)
94 }
95}
96
97pub struct Sequential;
98impl Joiner for Sequential {
99 #[inline]
100 fn is_parallel() -> bool {
101 false
102 }
103 #[inline]
104 fn join<A, R_A, B, R_B>(oper_a: A, oper_b: B) -> (R_A, R_B)
105 where
106 A: FnOnce() -> R_A + Send,
107 B: FnOnce() -> R_B + Send,
108 R_A: Send,
109 R_B: Send,
110 {
111 let a = oper_a();
112 let b = oper_b();
113 (a, b)
114 }
115}