Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix deep_size_of_interned always returns a fixed value (close #51) #52

Merged
merged 7 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
impl<T: ?Sized + deepsize::DeepSizeOf> deepsize::DeepSizeOf for Arena<T> {
fn deep_size_of_children(&self, context: &mut deepsize::Context) -> usize {
let hashset = self.data.lock().unwrap();
hashset.deep_size_of_children(context)
(*hashset).deep_size_of_children(context)
}
}

Expand Down Expand Up @@ -474,7 +474,7 @@

impl<'a, T: ?Sized> PartialEq for ArenaIntern<'a, T> {
fn eq(&self, other: &Self) -> bool {
self.get_pointer() == other.get_pointer()

Check warning on line 477 in src/arena.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

ambiguous wide pointer comparison, the comparison includes metadata which may not be expected

Check warning on line 477 in src/arena.rs

View workflow job for this annotation

GitHub Actions / coverage

ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
}
}
impl<'a, T: ?Sized> Eq for ArenaIntern<'a, T> {}
Expand Down
23 changes: 20 additions & 3 deletions src/boxedset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,26 @@ impl<P> HashSet<P> {
}

#[cfg(feature = "deepsize")]
impl<P: deepsize::DeepSizeOf> deepsize::DeepSizeOf for HashSet<P> {
impl<P: deepsize::DeepSizeOf> deepsize::DeepSizeOf for HashSet<&'static P> {
fn deep_size_of_children(&self, context: &mut deepsize::Context) -> usize {
let pointers = self.0.capacity() * std::mem::size_of::<P>();
let pointers = self.0.capacity() * std::mem::size_of::<&'static P>();
let heap_memory = self
.0
.keys()
.map(|n| n.deep_size_of_children(context))
.map(|n| (**n).deep_size_of_children(context) + std::mem::size_of::<P>())
.sum::<usize>();
pointers + heap_memory
}
}

#[cfg(feature = "deepsize")]
impl<P: deepsize::DeepSizeOf + ?Sized> deepsize::DeepSizeOf for HashSet<Box<P>> {
fn deep_size_of_children(&self, context: &mut deepsize::Context) -> usize {
let pointers = self.0.capacity() * std::mem::size_of::<Box<P>>();
let heap_memory = self
.0
.keys()
.map(|n| (**n).deep_size_of_children(context) + std::mem::size_of_val(&**n))
.sum::<usize>();
pointers + heap_memory
}
Expand Down Expand Up @@ -64,6 +77,10 @@ impl<P: Deref + Eq + Hash> HashSet<P> {
pub fn len(&self) -> usize {
self.0.len()
}
#[allow(dead_code)] // maybe unused without `deepsize` feature
pub fn capacity(&self) -> usize {
self.0.capacity()
}
#[cfg(feature = "bench")]
pub fn clear(&mut self) {
self.0.clear()
Expand Down
128 changes: 125 additions & 3 deletions src/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ use tinyset::Fits64;
/// assert_eq!(y, Intern::from("world"));
/// assert_eq!(&*x, "hello"); // dereference a Intern like a pointer
/// ```

#[test]
fn like_doctest_intern() {
let x = Intern::new("hello".to_string());
Expand Down Expand Up @@ -76,7 +75,7 @@ impl<T: 'static + ?Sized> deepsize::DeepSizeOf for Intern<T> {
pub fn deep_size_of_interned<T: Eq + Hash + Send + Sync + 'static + deepsize::DeepSizeOf>() -> usize
{
use deepsize::DeepSizeOf;
INTERN_CONTAINERS.with(|m: &mut HashSet<&'static T>| -> usize { m.deep_size_of() })
INTERN_CONTAINERS.with(|m: &mut HashSet<&'static T>| -> usize { (*m).deep_size_of() })
}

#[test]
Expand Down Expand Up @@ -409,7 +408,9 @@ impl<T: Eq + Hash + Send + Sync + Default + 'static> Default for Intern<T> {

#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
#[cfg(feature = "serde")]
impl<'de, T: Eq + Hash + Send + Sync + ?Sized + 'static + Deserialize<'de>> Deserialize<'de> for Intern<T> {
impl<'de, T: Eq + Hash + Send + Sync + ?Sized + 'static + Deserialize<'de>> Deserialize<'de>
for Intern<T>
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
T::deserialize(deserializer).map(|x: T| Self::new(x))
}
Expand All @@ -419,6 +420,17 @@ impl<'de, T: Eq + Hash + Send + Sync + ?Sized + 'static + Deserialize<'de>> Dese
mod intern_tests {
use super::Intern;
use super::{Borrow, Deref};
use std::hash::Hash;

#[cfg(feature = "deepsize")]
use super::INTERN_CONTAINERS;
#[cfg(feature = "deepsize")]
use crate::{boxedset::HashSet, deep_size_of_interned};
#[cfg(feature = "deepsize")]
use deepsize::{Context, DeepSizeOf};
#[cfg(feature = "deepsize")]
use std::sync::Arc;

#[test]
fn eq_string() {
assert_eq!(Intern::new("hello"), Intern::new("hello"));
Expand Down Expand Up @@ -506,6 +518,116 @@ mod intern_tests {
h.join().unwrap()
}
}

#[cfg(feature = "deepsize")]
#[test]
fn test_deep_size() {
let string1 = String::from("abcdefghijklmnopqrstuvwxyz");
let string2 = string1.clone();
let string3 = string1.clone();
// 3 string are the same, interned only once
let string_size = string1.deep_size_of();

let _ = Intern::new(string1);
let _ = Intern::new(string2);
let _ = Intern::new(string3);
// size of set
let set_size =
INTERN_CONTAINERS.with(|m: &mut HashSet<&'static String>| std::mem::size_of_val(m));
// size of pointers in the set
let pointers_in_set_size = INTERN_CONTAINERS.with(|m: &mut HashSet<&'static String>| {
std::mem::size_of::<&'static String>() * m.capacity()
});

let interned_size = deep_size_of_interned::<String>();
assert_eq!(interned_size, string_size + set_size + pointers_in_set_size);
}

#[cfg(feature = "deepsize")]
#[derive(Clone)]
struct ArcInside {
hash: usize,
pointer: Arc<String>,
}

#[cfg(feature = "deepsize")]
impl Hash for ArcInside {
/// For testing purposes, we only hash the hash field.
/// In order to make [`ArcInside`] instances containing the same string have different hash values.
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.hash.hash(state);
}
}

#[cfg(feature = "deepsize")]
impl PartialEq for ArcInside {
/// For testing purposes, we only compare the hash field.
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}

#[cfg(feature = "deepsize")]
impl Eq for ArcInside {}

#[cfg(feature = "deepsize")]
impl DeepSizeOf for ArcInside {
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.pointer.deep_size_of_children(context)
}
}

#[cfg(feature = "deepsize")]
#[test]
fn test_deep_size_with_context() {
let string = String::from("abcdefghijklmnopqrstuvwxyz");
// size of string inside arc, 50 bytes.
// Three arcs pointed to the same string will not be counted multiple times.
let string_size = string.deep_size_of();

let a1 = ArcInside {
hash: 1,
pointer: Arc::new(string),
};
let a2 = ArcInside {
hash: 2,
pointer: a1.pointer.clone(),
};
let a3 = ArcInside {
hash: 3,
pointer: a1.pointer.clone(),
};
// size of ArcInside, 16 bytes each
let object_size = std::mem::size_of::<ArcInside>() * 3;

let _ = Intern::new(a1);
let _ = Intern::new(a2);
let _ = Intern::new(a3);

// size of set
let set_size =
INTERN_CONTAINERS.with(|m: &mut HashSet<&'static ArcInside>| std::mem::size_of_val(m));
// size of pointers in the set
let pointers_in_set_size = INTERN_CONTAINERS.with(|m: &mut HashSet<&'static ArcInside>| {
std::mem::size_of::<&'static ArcInside>() * m.capacity()
});

let interned_size = deep_size_of_interned::<ArcInside>();

println!("string_size: {}", string_size);
println!("object_size: {}", object_size);
println!("set_size: {}", set_size);
println!("pointers_in_set_size: {}", pointers_in_set_size);
println!("interned_size: {}", interned_size);

// 3 ArcInside has different hash values
INTERN_CONTAINERS.with(|m: &mut HashSet<&'static ArcInside>| assert_eq!(m.len(), 3));

assert_eq!(
interned_size,
string_size + object_size + set_size + pointers_in_set_size
);
}
}

impl<T: Debug + ?Sized> Debug for Intern<T> {
Expand Down
Loading