From 1686bd8de8060f8028f63e70508da1bf0cfe9329 Mon Sep 17 00:00:00 2001 From: David Herberth Date: Wed, 5 Mar 2025 14:15:28 +0100 Subject: [PATCH] ref(byteview): Expose API to apply access hints --- CHANGELOG.md | 6 +++ symbolic-common/src/byteview.rs | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f6b57e0a..e58aac503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Features** + +- Expose API to apply access pattern hints to a `ByteView`.([#899](https://github.com/getsentry/symbolic/pull/899)). + ## 12.13.2 **Fixes** diff --git a/symbolic-common/src/byteview.rs b/symbolic-common/src/byteview.rs index f535a6111..de1c777e1 100644 --- a/symbolic-common/src/byteview.rs +++ b/symbolic-common/src/byteview.rs @@ -233,6 +233,37 @@ impl<'a> ByteView<'a> { pub fn as_slice(&self) -> &[u8] { self.backing.deref() } + + /// Applies a [`AccessPattern`] hint to the backing storage. + /// + /// A hint can be applied when the predominantly access pattern + /// for this byte view is known. + /// + /// Applying the wrong hint may have significant effects on performance. + /// + /// Hints are applied on best effort basis, not all platforms + /// support the same hints, not all backing storages support + /// hints. + /// + /// # Example + /// + /// ``` + /// use std::io::Write; + /// use symbolic_common::{ByteView, AccessPattern}; + /// + /// fn main() -> Result<(), std::io::Error> { + /// let mut file = tempfile::tempfile()?; + /// let view = ByteView::map_file_ref(&file)?; + /// let _ = view.hint(AccessPattern::Random); + /// Ok(()) + /// } + /// ``` + pub fn hint(&self, hint: AccessPattern) -> Result<(), io::Error> { + match self.backing.deref() { + ByteViewBacking::Buf(_) => Ok(()), + ByteViewBacking::Mmap(mmap) => mmap.advise(hint.to_madvise()), + } + } } impl AsRef<[u8]> for ByteView<'_> { @@ -253,6 +284,44 @@ impl Deref for ByteView<'_> { unsafe impl StableDeref for ByteView<'_> {} +/// Values supported by [`ByteView::hint`]. +/// +/// This is largely an abstraction over [`madvise(2)`] and [`fadvise(2)`]. +/// +/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html +/// [`fadvise(2)`]: https://man7.org/linux/man-pages/man2/posix_fadvise.2.html +#[derive(Debug, Default)] +pub enum AccessPattern { + /// No special treatment. + /// + /// The operating system is in full control of the buffer, + /// a generally good default. + /// + /// This is the default. + #[default] + Normal, + /// Expect access to be random. + /// + /// Read ahead might be less useful than normally. + Rnadom, + /// Expect access to be in sequential order, read ahead might be very useful. + /// After reading data there is a high chance it will not be accessed again + /// and can be aggressively freed. + Sequential, +} + +impl AccessPattern { + fn to_madvise(self) -> memmap2::Advice { + match self { + AccessPattern::Normal => memmap2::Advice::Normal, + AccessPattern::Rnadom => memmap2::Advice::Random, + AccessPattern::Sequential => memmap2::Advice::Sequential, + } + } +} + + + #[cfg(test)] mod tests { use super::*;