Skip to main content

rustfs_erasure_codec/galois_8/
profile.rs

1#[cfg(feature = "std")]
2use core::sync::atomic::{AtomicUsize, Ordering};
3#[cfg(feature = "std")]
4use std::sync::OnceLock;
5
6#[cfg(feature = "std")]
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
8pub struct RustNeonProfileStats {
9    pub mul_calls: usize,
10    pub mul_xor_calls: usize,
11    pub total_bytes: usize,
12    pub vector_64b_chunks: usize,
13    pub vector_16b_chunks: usize,
14    pub tail_bytes: usize,
15    pub tail_calls: usize,
16    pub table_lookups: usize,
17}
18
19#[cfg(feature = "std")]
20impl RustNeonProfileStats {
21    pub fn saturating_sub(self, baseline: Self) -> Self {
22        Self {
23            mul_calls: self.mul_calls.saturating_sub(baseline.mul_calls),
24            mul_xor_calls: self.mul_xor_calls.saturating_sub(baseline.mul_xor_calls),
25            total_bytes: self.total_bytes.saturating_sub(baseline.total_bytes),
26            vector_64b_chunks: self
27                .vector_64b_chunks
28                .saturating_sub(baseline.vector_64b_chunks),
29            vector_16b_chunks: self
30                .vector_16b_chunks
31                .saturating_sub(baseline.vector_16b_chunks),
32            tail_bytes: self.tail_bytes.saturating_sub(baseline.tail_bytes),
33            tail_calls: self.tail_calls.saturating_sub(baseline.tail_calls),
34            table_lookups: self.table_lookups.saturating_sub(baseline.table_lookups),
35        }
36    }
37}
38
39#[cfg(feature = "std")]
40#[derive(Debug, Default)]
41pub(crate) struct RustNeonProfileMetrics {
42    mul_calls: AtomicUsize,
43    mul_xor_calls: AtomicUsize,
44    total_bytes: AtomicUsize,
45    vector_64b_chunks: AtomicUsize,
46    vector_16b_chunks: AtomicUsize,
47    tail_bytes: AtomicUsize,
48    tail_calls: AtomicUsize,
49    table_lookups: AtomicUsize,
50}
51
52#[cfg(feature = "std")]
53impl RustNeonProfileMetrics {
54    fn snapshot(&self) -> RustNeonProfileStats {
55        RustNeonProfileStats {
56            mul_calls: self.mul_calls.load(Ordering::Relaxed),
57            mul_xor_calls: self.mul_xor_calls.load(Ordering::Relaxed),
58            total_bytes: self.total_bytes.load(Ordering::Relaxed),
59            vector_64b_chunks: self.vector_64b_chunks.load(Ordering::Relaxed),
60            vector_16b_chunks: self.vector_16b_chunks.load(Ordering::Relaxed),
61            tail_bytes: self.tail_bytes.load(Ordering::Relaxed),
62            tail_calls: self.tail_calls.load(Ordering::Relaxed),
63            table_lookups: self.table_lookups.load(Ordering::Relaxed),
64        }
65    }
66
67    fn reset(&self) {
68        self.mul_calls.store(0, Ordering::Relaxed);
69        self.mul_xor_calls.store(0, Ordering::Relaxed);
70        self.total_bytes.store(0, Ordering::Relaxed);
71        self.vector_64b_chunks.store(0, Ordering::Relaxed);
72        self.vector_16b_chunks.store(0, Ordering::Relaxed);
73        self.tail_bytes.store(0, Ordering::Relaxed);
74        self.tail_calls.store(0, Ordering::Relaxed);
75        self.table_lookups.store(0, Ordering::Relaxed);
76    }
77
78    #[cfg(all(
79        feature = "simd-neon",
80        target_arch = "aarch64",
81        not(target_env = "msvc"),
82        not(any(target_os = "android", target_os = "ios"))
83    ))]
84    pub(crate) fn record_call(
85        &self,
86        is_xor: bool,
87        input_len: usize,
88        vector_64b_chunks: usize,
89        vector_16b_chunks: usize,
90        tail_bytes: usize,
91    ) {
92        if is_xor {
93            self.mul_xor_calls.fetch_add(1, Ordering::Relaxed);
94        } else {
95            self.mul_calls.fetch_add(1, Ordering::Relaxed);
96        }
97        self.total_bytes.fetch_add(input_len, Ordering::Relaxed);
98        self.vector_64b_chunks
99            .fetch_add(vector_64b_chunks, Ordering::Relaxed);
100        self.vector_16b_chunks
101            .fetch_add(vector_16b_chunks, Ordering::Relaxed);
102        if tail_bytes > 0 {
103            self.tail_calls.fetch_add(1, Ordering::Relaxed);
104            self.tail_bytes.fetch_add(tail_bytes, Ordering::Relaxed);
105        }
106        let lookups = vector_64b_chunks
107            .saturating_mul(8)
108            .saturating_add(vector_16b_chunks.saturating_mul(2));
109        self.table_lookups.fetch_add(lookups, Ordering::Relaxed);
110    }
111}
112
113#[cfg(feature = "std")]
114pub(crate) static RUST_NEON_PROFILE_METRICS: RustNeonProfileMetrics = RustNeonProfileMetrics {
115    mul_calls: AtomicUsize::new(0),
116    mul_xor_calls: AtomicUsize::new(0),
117    total_bytes: AtomicUsize::new(0),
118    vector_64b_chunks: AtomicUsize::new(0),
119    vector_16b_chunks: AtomicUsize::new(0),
120    tail_bytes: AtomicUsize::new(0),
121    tail_calls: AtomicUsize::new(0),
122    table_lookups: AtomicUsize::new(0),
123};
124
125#[cfg(feature = "std")]
126const RS_NEON_MUL_SLICE_XOR_UNROLL_ENV: &str = "RS_NEON_MUL_SLICE_XOR_UNROLL";
127#[cfg(feature = "std")]
128pub(crate) const RS_NEON_MUL_SLICE_XOR_SCHEDULE_ENV: &str = "RS_NEON_MUL_SLICE_XOR_SCHEDULE";
129
130#[cfg(feature = "std")]
131pub(crate) fn parse_rust_neon_xor_unroll(value: &str) -> Option<usize> {
132    match value {
133        "2" => Some(2),
134        "4" => Some(4),
135        _ => None,
136    }
137}
138
139#[cfg(feature = "std")]
140pub(crate) fn rust_neon_mul_slice_xor_unroll() -> usize {
141    static UNROLL: OnceLock<usize> = OnceLock::new();
142    *UNROLL.get_or_init(|| {
143        std::env::var(RS_NEON_MUL_SLICE_XOR_UNROLL_ENV)
144            .ok()
145            .as_deref()
146            .and_then(parse_rust_neon_xor_unroll)
147            .unwrap_or(4)
148    })
149}
150
151#[cfg(feature = "std")]
152pub(crate) fn rust_neon_mul_slice_xor_schedule_split() -> bool {
153    static SPLIT: OnceLock<bool> = OnceLock::new();
154    *SPLIT.get_or_init(|| {
155        std::env::var(RS_NEON_MUL_SLICE_XOR_SCHEDULE_ENV)
156            .ok()
157            .is_some_and(|value| value == "split")
158    })
159}
160
161#[cfg(feature = "std")]
162pub fn rust_neon_profile_stats() -> RustNeonProfileStats {
163    RUST_NEON_PROFILE_METRICS.snapshot()
164}
165
166#[cfg(feature = "std")]
167pub fn reset_rust_neon_profile_stats() {
168    RUST_NEON_PROFILE_METRICS.reset();
169}