Skip to content

Commit a3b78e0

Browse files
committed
add core::hint::prefetch_{read, write}_{data, instruction}
well, we don't expose `prefetch_write_instruction`, that one doesn't really make sense in practice.
1 parent d5525a7 commit a3b78e0

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

library/core/src/hint.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,3 +823,115 @@ where
823823
crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init()
824824
}
825825
}
826+
827+
/// The expected temporal locality of a memory prefetch operation.
828+
///
829+
/// Locality expresses how likely the prefetched data is to be reused soon,
830+
/// and therefore which level of cache it should be brought into.
831+
///
832+
/// The locality is just a hint, and may be ignored on some targets or by the hardware.
833+
///
834+
/// Used with functions like [`prefetch_read_data`] and [`prefetch_write_data`].
835+
///
836+
/// [`prefetch_read_data`]: crate::hint::prefetch_read_data
837+
/// [`prefetch_write_data`]: crate::hint::prefetch_write_data
838+
#[unstable(feature = "hint_prefetch", issue = "146941")]
839+
#[non_exhaustive]
840+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
841+
pub enum Locality {
842+
/// Data is unlikely to be reused soon.
843+
///
844+
/// Typically bypasses the caches so they are not polluted.
845+
NonTemporal = 0,
846+
/// Data is expected to be reused eventually.
847+
///
848+
/// Typically prefetches into L3 cache (if the CPU supports it).
849+
L3 = 1,
850+
/// Data is expected to be reused in the near future.
851+
///
852+
/// Typically prefetches into L2 cache.
853+
L2 = 2,
854+
/// Data is expected to be reused very soon.
855+
///
856+
/// Typically prefetches into L1 cache.
857+
L1 = 3,
858+
}
859+
860+
/// Prefetch the cache line containing `ptr` for a future read.
861+
///
862+
/// A strategically placed prefetch can reduce cache miss latency if the data is accessed
863+
/// soon after, but may also increase bandwidth usage or evict other cache lines.
864+
///
865+
/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware.
866+
///
867+
/// Passing a dangling or invalid pointer is permitted: the memory will not
868+
/// actually be dereferenced, and no faults are raised.
869+
///
870+
/// # Examples
871+
///
872+
/// ```
873+
/// use std::hint::{Locality, prefetch_read_data};
874+
/// use std::mem::size_of_val;
875+
///
876+
/// // Prefetch all of `slice` into the L1 cache.
877+
/// fn prefetch_slice<T>(slice: &[T]) {
878+
/// // On most systems the cache line size is 64 bytes.
879+
/// for offset in (0..size_of_val(slice)).step_by(64) {
880+
/// prefetch_read_data(slice.as_ptr().wrapping_add(offset), Locality::L1);
881+
/// }
882+
/// }
883+
/// ```
884+
#[inline(always)]
885+
#[unstable(feature = "hint_prefetch", issue = "146941")]
886+
pub const fn prefetch_read_data<T>(ptr: *const T, locality: Locality) {
887+
match locality {
888+
Locality::NonTemporal => {
889+
intrinsics::prefetch_read_data::<T, { Locality::NonTemporal as i32 }>(ptr)
890+
}
891+
Locality::L3 => intrinsics::prefetch_read_data::<T, { Locality::L3 as i32 }>(ptr),
892+
Locality::L2 => intrinsics::prefetch_read_data::<T, { Locality::L2 as i32 }>(ptr),
893+
Locality::L1 => intrinsics::prefetch_read_data::<T, { Locality::L1 as i32 }>(ptr),
894+
}
895+
}
896+
897+
/// Prefetch the cache line containing `ptr` for a future write.
898+
///
899+
/// A strategically placed prefetch can reduce cache miss latency if the data is accessed
900+
/// soon after, but may also increase bandwidth usage or evict other cache lines.
901+
///
902+
/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware.
903+
///
904+
/// Passing a dangling or invalid pointer is permitted: the memory will not
905+
/// actually be dereferenced, and no faults are raised.
906+
#[unstable(feature = "hint_prefetch", issue = "146941")]
907+
pub const fn prefetch_write_data<T>(ptr: *mut T, locality: Locality) {
908+
match locality {
909+
Locality::NonTemporal => {
910+
intrinsics::prefetch_write_data::<T, { Locality::NonTemporal as i32 }>(ptr)
911+
}
912+
Locality::L3 => intrinsics::prefetch_write_data::<T, { Locality::L3 as i32 }>(ptr),
913+
Locality::L2 => intrinsics::prefetch_write_data::<T, { Locality::L2 as i32 }>(ptr),
914+
Locality::L1 => intrinsics::prefetch_write_data::<T, { Locality::L1 as i32 }>(ptr),
915+
}
916+
}
917+
918+
/// Prefetch the cache line containing `ptr` for a future read.
919+
///
920+
/// A strategically placed prefetch can reduce cache miss latency if the instructions are
921+
/// accessed soon after, but may also increase bandwidth usage or evict other cache lines.
922+
///
923+
/// A prefetch is a *hint*, and may be ignored on certain targets or by the hardware.
924+
///
925+
/// Passing a dangling or invalid pointer is permitted: the memory will not
926+
/// actually be dereferenced, and no faults are raised.
927+
#[unstable(feature = "hint_prefetch", issue = "146941")]
928+
pub const fn prefetch_read_instruction<T>(ptr: *const T, locality: Locality) {
929+
match locality {
930+
Locality::NonTemporal => {
931+
intrinsics::prefetch_read_instruction::<T, { Locality::NonTemporal as i32 }>(ptr)
932+
}
933+
Locality::L3 => intrinsics::prefetch_read_instruction::<T, { Locality::L3 as i32 }>(ptr),
934+
Locality::L2 => intrinsics::prefetch_read_instruction::<T, { Locality::L2 as i32 }>(ptr),
935+
Locality::L1 => intrinsics::prefetch_read_instruction::<T, { Locality::L1 as i32 }>(ptr),
936+
}
937+
}

0 commit comments

Comments
 (0)