1use std::sync::LazyLock;
2
3pub static PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| {
4 #[cfg(target_family = "unix")]
5 unsafe {
6 libc::sysconf(libc::_SC_PAGESIZE) as usize
7 }
8 #[cfg(not(target_family = "unix"))]
9 {
10 4096
11 }
12});
13
14pub mod prefetch {
15 use super::PAGE_SIZE;
16
17 #[inline]
21 unsafe fn prefetch_l2_impl(ptr: *const u8) {
22 _ = ptr; #[cfg(target_arch = "x86_64")]
25 {
26 use std::arch::x86_64::*;
27 unsafe { _mm_prefetch(ptr as *const _, _MM_HINT_T1) };
28 }
29
30 #[cfg(all(target_arch = "aarch64", feature = "nightly"))]
31 {
32 use std::arch::aarch64::*;
33 unsafe { _prefetch(ptr as *const _, _PREFETCH_READ, _PREFETCH_LOCALITY2) };
34 }
35 }
36
37 pub fn prefetch_l2(slice: &[u8]) {
39 if slice.is_empty() {
40 return;
41 }
42
43 for i in (0..slice.len()).step_by(*PAGE_SIZE) {
48 unsafe { prefetch_l2_impl(slice[i..].as_ptr()) };
49 }
50
51 unsafe { prefetch_l2_impl(slice[slice.len() - 1..].as_ptr()) }
52 }
53
54 pub fn madvise_sequential(#[allow(unused)] slice: &[u8]) {
56 #[cfg(target_family = "unix")]
57 madvise(slice, libc::MADV_SEQUENTIAL);
58 }
59
60 pub fn madvise_willneed(#[allow(unused)] slice: &[u8]) {
62 #[cfg(target_family = "unix")]
63 madvise(slice, libc::MADV_WILLNEED);
64 }
65
66 pub fn madvise_populate_read(#[allow(unused)] slice: &[u8]) {
68 #[cfg(target_os = "linux")]
69 madvise(slice, libc::MADV_POPULATE_READ);
70 }
71
72 pub fn force_populate_read(slice: &[u8]) {
74 for i in (0..slice.len()).step_by(*PAGE_SIZE) {
75 std::hint::black_box(slice[i]);
76 }
77
78 std::hint::black_box(slice.last().copied());
79 }
80
81 #[cfg(target_family = "unix")]
82 fn madvise(slice: &[u8], advice: libc::c_int) {
83 if slice.is_empty() {
84 return;
85 }
86 let ptr = slice.as_ptr();
87
88 let align = ptr as usize % *PAGE_SIZE;
89 let ptr = ptr.wrapping_sub(align);
90 let len = slice.len() + align;
91
92 if unsafe { libc::madvise(ptr as *mut libc::c_void, len, advice) } != 0 {
93 let err = std::io::Error::last_os_error();
94 if let std::io::ErrorKind::InvalidInput = err.kind() {
95 panic!("{}", err);
96 }
97 }
98 }
99
100 pub fn no_prefetch(_: &[u8]) {}
101
102 pub fn get_memory_prefetch_func(verbose: bool) -> fn(&[u8]) -> () {
104 let memory_prefetch_func = match std::env::var("POLARS_MEMORY_PREFETCH").ok().as_deref() {
105 None => {
106 #[cfg(target_family = "unix")]
109 {
110 madvise_willneed
111 }
112 #[cfg(not(target_family = "unix"))]
113 {
114 no_prefetch
115 }
116 },
117 Some("no_prefetch") => no_prefetch,
118 Some("prefetch_l2") => prefetch_l2,
119 Some("madvise_sequential") => {
120 #[cfg(target_family = "unix")]
121 {
122 madvise_sequential
123 }
124 #[cfg(not(target_family = "unix"))]
125 {
126 panic!(
127 "POLARS_MEMORY_PREFETCH=madvise_sequential is not supported by this system"
128 );
129 }
130 },
131 Some("madvise_willneed") => {
132 #[cfg(target_family = "unix")]
133 {
134 madvise_willneed
135 }
136 #[cfg(not(target_family = "unix"))]
137 {
138 panic!(
139 "POLARS_MEMORY_PREFETCH=madvise_willneed is not supported by this system"
140 );
141 }
142 },
143 Some("madvise_populate_read") => {
144 #[cfg(target_os = "linux")]
145 {
146 madvise_populate_read
147 }
148 #[cfg(not(target_os = "linux"))]
149 {
150 panic!(
151 "POLARS_MEMORY_PREFETCH=madvise_populate_read is not supported by this system"
152 );
153 }
154 },
155 Some("force_populate_read") => force_populate_read,
156 Some(v) => panic!("invalid value for POLARS_MEMORY_PREFETCH: {v}"),
157 };
158
159 if verbose {
160 let func_name = match memory_prefetch_func as usize {
161 v if v == no_prefetch as *const () as usize => "no_prefetch",
162 v if v == prefetch_l2 as *const () as usize => "prefetch_l2",
163 v if v == madvise_sequential as *const () as usize => "madvise_sequential",
164 v if v == madvise_willneed as *const () as usize => "madvise_willneed",
165 v if v == madvise_populate_read as *const () as usize => "madvise_populate_read",
166 v if v == force_populate_read as *const () as usize => "force_populate_read",
167 _ => unreachable!(),
168 };
169
170 eprintln!("memory prefetch function: {func_name}");
171 }
172
173 memory_prefetch_func
174 }
175}