god_graph/utils/cache.rs
1//! Cache 优化和预取工具
2//!
3//! 提供 CPU 缓存优化功能,包括:
4//! - 64 字节对齐的填充类型,避免多线程访问时的 false sharing
5//! - 软件预取指令,提前将数据加载到 CPU 缓存
6//!
7//! ## 使用示例
8//!
9//! ```rust
10//! use god_gragh::utils::cache::{Padded, prefetch_read};
11//!
12//! // 创建对齐的填充值
13//! let padded = Padded::new(42);
14//! assert_eq!(*padded, 42);
15//!
16//! // 预取数据到缓存
17//! let data = vec![1, 2, 3, 4, 5];
18//! prefetch_read(&data[0]);
19//! ```
20
21/// 64 字节对齐的填充类型,避免 false sharing
22///
23/// 在多线程环境中,当多个线程访问相邻内存时,
24/// 即使访问不同的变量,也可能因为缓存行共享而导致性能下降。
25/// `Padded<T>` 通过将数据填充到 64 字节(缓存行大小)来避免这个问题。
26///
27/// ## 类型参数
28///
29/// - `T`: 要包装的数据类型
30///
31/// ## 示例
32///
33/// ```rust
34/// use god_gragh::utils::cache::Padded;
35///
36/// let padded = Padded::new(42);
37/// assert_eq!(*padded, 42);
38/// assert!(Padded::<u8>::size() >= 64); // 至少 64 字节
39/// ```
40#[repr(align(64))]
41#[derive(Debug, Clone, Copy)]
42pub struct Padded<T> {
43 /// 包装的数据
44 pub data: T,
45 /// 填充字节,确保 64 字节对齐
46 _padding: [u8; 64],
47}
48
49impl<T> Padded<T> {
50 /// 创建新的 Padded 包装
51 ///
52 /// ## 参数
53 ///
54 /// - `data`: 要包装的数据
55 ///
56 /// ## 示例
57 ///
58 /// ```rust
59 /// use god_gragh::utils::cache::Padded;
60 ///
61 /// let padded = Padded::new(42);
62 /// assert_eq!(padded.data, 42);
63 /// ```
64 pub fn new(data: T) -> Self {
65 Self {
66 data,
67 _padding: [0; 64],
68 }
69 }
70
71 /// 获取 Padded 结构的大小(字节)
72 ///
73 /// 返回值总是 >= 64,因为缓存行对齐
74 pub fn size() -> usize {
75 core::mem::size_of::<Self>()
76 }
77
78 /// 验证指针是否 64 字节对齐
79 ///
80 /// ## 参数
81 ///
82 /// - `ptr`: 要验证的指针
83 ///
84 /// ## 返回
85 ///
86 /// - `true`: 对齐正确
87 /// - `false`: 对齐错误
88 ///
89 /// ## 示例
90 ///
91 /// ```rust
92 /// use god_gragh::utils::cache::Padded;
93 ///
94 /// let padded = Padded::new(42);
95 /// assert!(Padded::is_aligned(&padded));
96 /// ```
97 pub fn is_aligned(ptr: &T) -> bool {
98 (ptr as *const T as usize) % 64 == 0
99 }
100
101 /// 验证 Vec 中 T 的指针是否 64 字节对齐
102 ///
103 /// ## 参数
104 ///
105 /// - `vec`: 要验证的 Vec
106 ///
107 /// ## 返回
108 ///
109 /// - `true`: 对齐正确
110 /// - `false`: 对齐错误
111 ///
112 /// ## 示例
113 ///
114 /// ```rust
115 /// use god_gragh::utils::cache::Padded;
116 ///
117 /// let vec: Vec<Padded<u8>> = vec![Padded::new(1), Padded::new(2)];
118 /// assert!(Padded::is_vec_aligned(&vec));
119 /// ```
120 pub fn is_vec_aligned(vec: &[T]) -> bool {
121 if vec.is_empty() {
122 return true;
123 }
124 (vec.as_ptr() as usize) % 64 == 0
125 }
126}
127
128impl<T> core::ops::Deref for Padded<T> {
129 type Target = T;
130
131 fn deref(&self) -> &Self::Target {
132 &self.data
133 }
134}
135
136impl<T> core::ops::DerefMut for Padded<T> {
137 fn deref_mut(&mut self) -> &mut Self::Target {
138 &mut self.data
139 }
140}
141
142impl<T: Default> Default for Padded<T> {
143 fn default() -> Self {
144 Self::new(T::default())
145 }
146}
147
148/// 预取数据到 CPU 缓存用于读取
149///
150/// 使用 CPU 的 prefetch 指令提前将数据加载到缓存中,
151/// 可以减少后续访问的延迟。这是一个性能优化提示,
152/// 在某些架构上可能被忽略。
153///
154/// ## 参数
155///
156/// - `data`: 要预取的数据
157///
158/// ## 平台支持
159///
160/// - x86_64: 使用 `_mm_prefetch` 指令
161/// - 其他架构:使用 `std::hint::prefetch_read_data`(需要 std)
162///
163/// ## 示例
164///
165/// ```rust
166/// use god_gragh::utils::cache::prefetch_read;
167///
168/// let data = vec![1, 2, 3, 4, 5];
169/// prefetch_read(&data[0]);
170/// // 现在访问 data[0] 可能更快
171/// ```
172#[inline]
173pub fn prefetch_read<T>(data: &T) {
174 #[cfg(target_arch = "x86_64")]
175 // SAFETY: `_mm_prefetch` 是 CPU 内置指令,仅读取缓存不修改内存,
176 // 指针由 Rust 引用转换而来,保证有效且对齐
177 unsafe {
178 core::arch::x86_64::_mm_prefetch(
179 data as *const T as *const i8,
180 core::arch::x86_64::_MM_HINT_T0,
181 );
182 }
183
184 #[cfg(not(target_arch = "x86_64"))]
185 {
186 #[cfg(feature = "std")]
187 // SAFETY: `prefetch_read_data` 仅预取数据到缓存,不修改内存,
188 // 指针有效且大小正确
189 unsafe {
190 std::hint::prefetch_read_data(data as *const T as *const _, core::mem::size_of::<T>());
191 }
192 }
193}
194
195/// 预取数据到 CPU 缓存用于写入
196///
197/// 使用 CPU 的 prefetch 指令提前将数据加载到缓存中,
198/// 为后续的写入操作做准备。
199///
200/// ## 参数
201///
202/// - `data`: 要预取的数据
203///
204/// ## 平台支持
205///
206/// - x86_64: 使用 `_mm_prefetch` 指令
207/// - 其他架构:无操作(空实现)
208///
209/// ## 示例
210///
211/// ```rust
212/// use god_gragh::utils::cache::prefetch_write;
213///
214/// let mut data = vec![1, 2, 3, 4, 5];
215/// prefetch_write(&mut data[0]);
216/// // 现在写入 data[0] 可能更快
217/// ```
218#[inline]
219pub fn prefetch_write<T>(data: &mut T) {
220 #[cfg(target_arch = "x86_64")]
221 // SAFETY: `_mm_prefetch` 是 CPU 内置指令,预取到缓存用于后续写入,
222 // 可变引用保证指针有效且独占访问
223 unsafe {
224 core::arch::x86_64::_mm_prefetch(
225 data as *mut T as *const i8,
226 core::arch::x86_64::_MM_HINT_T0,
227 );
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
236 fn test_padded_size() {
237 assert!(Padded::<u8>::size() >= 64);
238 }
239
240 #[test]
241 fn test_padded_deref() {
242 let padded = Padded::new(42);
243 assert_eq!(*padded, 42);
244
245 let mut padded = Padded::new(42);
246 *padded = 43;
247 assert_eq!(padded.data, 43);
248 }
249}