Change GuestTracking to use a BTreeSet to remove performance bottleneck (#3112)

Co-authored-by: Your Name <you@example.com>
This commit is contained in:
WorksButNotTested 2025-03-28 19:13:34 +00:00 committed by GitHub
parent b67bd1792f
commit 36c748100e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 40 deletions

View File

@ -2,7 +2,7 @@
//! This implementation performs guest memory tracking by use of a simple sorted //! This implementation performs guest memory tracking by use of a simple sorted
//! list residing in the guest's user space. Hence no interaction with the host //! list residing in the guest's user space. Hence no interaction with the host
//! is required. //! is required.
use alloc::vec::Vec; use alloc::collections::BTreeSet;
use core::cmp::Ordering; use core::cmp::Ordering;
use log::debug; use log::debug;
@ -44,7 +44,7 @@ impl Ord for Range {
} }
} }
type Ranges = Vec<Range>; type Ranges = BTreeSet<Range>;
#[derive(Debug)] #[derive(Debug)]
pub struct GuestTracking { pub struct GuestTracking {
@ -66,20 +66,8 @@ impl Tracking for GuestTracking {
let item = Range { start, len }; let item = Range { start, len };
let pos = self.ranges.binary_search(&item); if !self.ranges.insert(item) {
match pos { Err(GuestTrackingError::TrackingConflict(start, len))?;
Ok(pos) => {
let conflict = &self.ranges[pos];
Err(GuestTrackingError::TrackingConflict(
conflict.start,
conflict.len,
item.start,
item.len,
))?;
}
Err(pos) => {
self.ranges.insert(pos, item);
}
} }
Ok(()) Ok(())
@ -87,20 +75,20 @@ impl Tracking for GuestTracking {
fn untrack(&mut self, start: GuestAddr) -> Result<(), Self::Error> { fn untrack(&mut self, start: GuestAddr) -> Result<(), Self::Error> {
debug!("dealloc - start: 0x{:x}", start); debug!("dealloc - start: 0x{:x}", start);
let pos = self.ranges.binary_search_by(|item| item.start.cmp(&start)); let item = Range { start, len: 1 };
match pos {
Ok(pos) => { if !self.ranges.remove(&item) {
self.ranges.remove(pos); Err(GuestTrackingError::AllocationNotFound(start))?;
Ok(())
}
Err(_pos) => Err(GuestTrackingError::AllocationNotFound(start)),
} }
Ok(())
} }
} }
impl GuestTracking { impl GuestTracking {
pub fn new() -> Result<Self, GuestTrackingError> { pub fn new() -> Result<Self, GuestTrackingError> {
Ok(GuestTracking { ranges: Vec::new() }) Ok(GuestTracking {
ranges: BTreeSet::new(),
})
} }
pub fn is_out_of_bounds(addr: GuestAddr, len: usize) -> bool { pub fn is_out_of_bounds(addr: GuestAddr, len: usize) -> bool {
@ -118,8 +106,8 @@ pub enum GuestTrackingError {
AddressRangeOverflow(GuestAddr, usize), AddressRangeOverflow(GuestAddr, usize),
#[error("Allocation not found: {0:x}")] #[error("Allocation not found: {0:x}")]
AllocationNotFound(GuestAddr), AllocationNotFound(GuestAddr),
#[error("Tracking conflict")] #[error("Tracking conflict: {0:x}, len: {1:x}")]
TrackingConflict(GuestAddr, usize, GuestAddr, usize), TrackingConflict(GuestAddr, usize),
#[error("Zero Length")] #[error("Zero Length")]
ZeroLength(GuestAddr), ZeroLength(GuestAddr),
} }

View File

@ -46,9 +46,7 @@ mod tests {
assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); assert_eq!(tracking.track(0x1000, 0x1000), Ok(()));
assert_eq!( assert_eq!(
tracking.track(0x1000, 0x1000), tracking.track(0x1000, 0x1000),
Err(GuestTrackingError::TrackingConflict( Err(GuestTrackingError::TrackingConflict(0x1000, 0x1000))
0x1000, 0x1000, 0x1000, 0x1000
))
); );
} }
@ -72,9 +70,7 @@ mod tests {
assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); assert_eq!(tracking.track(0x1000, 0x1000), Ok(()));
assert_eq!( assert_eq!(
tracking.track(0x0000, 0x1001), tracking.track(0x0000, 0x1001),
Err(GuestTrackingError::TrackingConflict( Err(GuestTrackingError::TrackingConflict(0x0000, 0x1001))
0x1000, 0x1000, 0x0000, 0x1001
))
); );
} }
@ -84,9 +80,7 @@ mod tests {
assert_eq!(tracking.track(0x1000, 0x1000), Ok(())); assert_eq!(tracking.track(0x1000, 0x1000), Ok(()));
assert_eq!( assert_eq!(
tracking.track(0x1fff, 0x1001), tracking.track(0x1fff, 0x1001),
Err(GuestTrackingError::TrackingConflict( Err(GuestTrackingError::TrackingConflict(0x1fff, 0x1001))
0x1000, 0x1000, 0x1fff, 0x1001
))
); );
} }
@ -100,8 +94,6 @@ mod tests {
assert_eq!( assert_eq!(
tracking.track(0xffffffffb5b60107, 0xdb), tracking.track(0xffffffffb5b60107, 0xdb),
Err(GuestTrackingError::TrackingConflict( Err(GuestTrackingError::TrackingConflict(
0xffffffffb5b5ff21,
0x3ff,
0xffffffffb5b60107, 0xffffffffb5b60107,
0xdb 0xdb
)) ))

View File

@ -86,9 +86,7 @@ fuzz_target!(|data: Vec<GuestAddr>| {
if overlaps { if overlaps {
assert_eq!( assert_eq!(
test_result, test_result,
Err(GuestTrackingError::TrackingConflict( Err(GuestTrackingError::TrackingConflict(test_start, test_len))
start, len, test_start, test_len
))
); );
} else { } else {
assert_eq!(test_result, Ok(())); assert_eq!(test_result, Ok(()));