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