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(&params, &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}