diff --git a/Cargo.toml b/Cargo.toml
index 6c12c3205..c2511404c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,4 +20,5 @@ members = [
"primitive-types",
"ethereum-types",
"ethbloom",
+ "parity-util-mem/derive"
]
diff --git a/parity-util-mem/Cargo.toml b/parity-util-mem/Cargo.toml
index a89122723..10a90c3cc 100644
--- a/parity-util-mem/Cargo.toml
+++ b/parity-util-mem/Cargo.toml
@@ -9,7 +9,6 @@ edition = "2018"
[dependencies]
cfg-if = "0.1.10"
-malloc_size_of_derive = "0.1.1"
dlmalloc = { version = "0.1.3", features = ["global"], optional = true }
wee_alloc = { version = "0.4.5", optional = true }
# from https://github.com/microsoft/mimalloc:
@@ -19,6 +18,7 @@ wee_alloc = { version = "0.4.5", optional = true }
# The performance penalty is only around 3% on average over our benchmarks.
mimallocator = { version = "0.1.3", features = ["secure"], optional = true }
mimalloc-sys = { version = "0.1.6", optional = true }
+parity-util-mem-derive = { path = "derive", version = "0.1" }
smallvec = { version = "1.0.0", optional = true }
ethereum-types = { version = "0.8.0", optional = true, path = "../ethereum-types" }
diff --git a/parity-util-mem/derive/Cargo.toml b/parity-util-mem/derive/Cargo.toml
new file mode 100644
index 000000000..f37d38013
--- /dev/null
+++ b/parity-util-mem/derive/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "parity-util-mem-derive"
+version = "0.1.0"
+authors = ["Parity Technologies"]
+license = "MIT"
+description = "Crate for memory reporting"
+repository = "https://github.com/paritytech/pariry-common/parity-util-mem/derive"
+
+[lib]
+path = "lib.rs"
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1"
+syn = { version = "1", features = ["full"] }
+synstructure = "0.12"
diff --git a/parity-util-mem/derive/lib.rs b/parity-util-mem/derive/lib.rs
new file mode 100644
index 000000000..c1c1e504e
--- /dev/null
+++ b/parity-util-mem/derive/lib.rs
@@ -0,0 +1,84 @@
+// Copyright 2015-2019 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+//! A crate for deriving the MallocSizeOf trait.
+//!
+//! This is a copy of Servo malloc_size_of_derive code, modified to work with
+//! our `parity_util_mem` library
+
+extern crate proc_macro2;
+#[macro_use]
+extern crate syn;
+#[macro_use]
+extern crate synstructure;
+
+#[cfg(not(test))]
+decl_derive!([MallocSizeOf, attributes(ignore_malloc_size_of)] => malloc_size_of_derive);
+
+fn malloc_size_of_derive(s: synstructure::Structure) -> proc_macro2::TokenStream {
+ let match_body = s.each(|binding| {
+ let ignore = binding.ast().attrs.iter().any(|attr| match attr.parse_meta().unwrap() {
+ syn::Meta::Path(ref path) | syn::Meta::List(syn::MetaList { ref path, .. })
+ if path.is_ident("ignore_malloc_size_of") =>
+ {
+ panic!(
+ "#[ignore_malloc_size_of] should have an explanation, \
+ e.g. #[ignore_malloc_size_of = \"because reasons\"]"
+ );
+ }
+ syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident("ignore_malloc_size_of") => true,
+ _ => false,
+ });
+ if ignore {
+ None
+ } else if let syn::Type::Array(..) = binding.ast().ty {
+ Some(quote! {
+ for item in #binding.iter() {
+ sum += parity_util_mem::MallocSizeOf::size_of(item, ops);
+ }
+ })
+ } else {
+ Some(quote! {
+ sum += parity_util_mem::MallocSizeOf::size_of(#binding, ops);
+ })
+ }
+ });
+
+ let ast = s.ast();
+ let name = &ast.ident;
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+ let mut where_clause = where_clause.unwrap_or(&parse_quote!(where)).clone();
+ for param in ast.generics.type_params() {
+ let ident = ¶m.ident;
+ where_clause.predicates.push(parse_quote!(#ident: parity_util_mem::MallocSizeOf));
+ }
+
+ let tokens = quote! {
+ impl #impl_generics parity_util_mem::MallocSizeOf for #name #ty_generics #where_clause {
+ #[inline]
+ #[allow(unused_variables, unused_mut, unreachable_code)]
+ fn size_of(&self, ops: &mut parity_util_mem::MallocSizeOfOps) -> usize {
+ let mut sum = 0;
+ match *self {
+ #match_body
+ }
+ sum
+ }
+ }
+ };
+
+ tokens
+}
diff --git a/parity-util-mem/src/impls.rs b/parity-util-mem/src/impls.rs
index 322375873..4124b132a 100644
--- a/parity-util-mem/src/impls.rs
+++ b/parity-util-mem/src/impls.rs
@@ -32,6 +32,12 @@ malloc_size_of_is_0!(std::time::Duration);
malloc_size_of_is_0!(U64, U128, U256, U512, H32, H64, H128, H160, H256, H264, H512, H520, Bloom);
+malloc_size_of_is_0!(
+ [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], [u8; 9], [u8; 10], [u8; 11], [u8; 12],
+ [u8; 13], [u8; 14], [u8; 15], [u8; 16], [u8; 17], [u8; 18], [u8; 19], [u8; 20], [u8; 21], [u8; 22], [u8; 23],
+ [u8; 24], [u8; 25], [u8; 26], [u8; 27], [u8; 28], [u8; 29], [u8; 30], [u8; 31], [u8; 32]
+);
+
macro_rules! impl_smallvec {
($size: expr) => {
impl MallocSizeOf for SmallVec<[T; $size]>
diff --git a/parity-util-mem/src/lib.rs b/parity-util-mem/src/lib.rs
index 43fbc4ab6..23c07e27b 100644
--- a/parity-util-mem/src/lib.rs
+++ b/parity-util-mem/src/lib.rs
@@ -23,8 +23,6 @@
#[cfg(not(feature = "std"))]
extern crate alloc;
-use malloc_size_of_derive as malloc_size_derive;
-
cfg_if::cfg_if! {
if #[cfg(all(
feature = "jemalloc-global",
@@ -72,7 +70,8 @@ pub mod impls;
pub use allocators::MallocSizeOfExt;
pub use malloc_size::{MallocSizeOf, MallocSizeOfOps};
-pub use malloc_size_derive::*;
+
+pub use parity_util_mem_derive::*;
#[cfg(feature = "std")]
#[cfg(test)]
diff --git a/parity-util-mem/src/malloc_size.rs b/parity-util-mem/src/malloc_size.rs
index a748eec82..a86823db5 100644
--- a/parity-util-mem/src/malloc_size.rs
+++ b/parity-util-mem/src/malloc_size.rs
@@ -43,8 +43,8 @@
//! measured as well as the thing it points to. E.g.
//! ` as MallocSizeOf>::size_of(field, ops)`.
-//! This is an extended (for own internal needs) version of the Servo internal malloc_size crate.
-//! We should occasionally track the upstream changes/fixes and reintroduce them here, be they applicable.
+//! This is an extended version of the Servo internal malloc_size crate.
+//! We should occasionally track the upstream changes/fixes and reintroduce them here, whenever applicable.
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
@@ -426,11 +426,7 @@ where
}
#[cfg(feature = "std")]
-impl MallocShallowSizeOf for std::collections::HashMap
-where
- K: Eq + Hash,
- S: BuildHasher,
-{
+impl MallocShallowSizeOf for std::collections::HashMap {
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
// See the implementation for std::collections::HashSet for details.
if ops.has_malloc_enclosing_size_of() {
@@ -444,9 +440,8 @@ where
#[cfg(feature = "std")]
impl MallocSizeOf for std::collections::HashMap
where
- K: Eq + Hash + MallocSizeOf,
+ K: MallocSizeOf,
V: MallocSizeOf,
- S: BuildHasher,
{
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let mut n = self.shallow_size_of(ops);
@@ -458,10 +453,7 @@ where
}
}
-impl MallocShallowSizeOf for rstd::collections::BTreeMap
-where
- K: Eq + Hash,
-{
+impl MallocShallowSizeOf for rstd::collections::BTreeMap {
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
if ops.has_malloc_enclosing_size_of() {
self.values().next().map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) })
@@ -473,7 +465,7 @@ where
impl MallocSizeOf for rstd::collections::BTreeMap
where
- K: Eq + Hash + MallocSizeOf,
+ K: MallocSizeOf,
V: MallocSizeOf,
{
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
diff --git a/parity-util-mem/tests/derive.rs b/parity-util-mem/tests/derive.rs
new file mode 100644
index 000000000..10dc6975d
--- /dev/null
+++ b/parity-util-mem/tests/derive.rs
@@ -0,0 +1,63 @@
+// Copyright 2015-2019 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use parity_util_mem::{MallocSizeOf, MallocSizeOfExt};
+
+#[test]
+#[cfg(feature = "std")]
+fn derive_vec() {
+ #[derive(MallocSizeOf)]
+ struct Trivia {
+ v: Vec,
+ }
+
+ let t = Trivia { v: vec![0u8; 1024] };
+
+ assert!(t.malloc_size_of() > 1000);
+}
+
+#[test]
+#[cfg(feature = "std")]
+fn derive_hashmap() {
+ #[derive(MallocSizeOf, Default)]
+ struct Trivia {
+ hm: std::collections::HashMap>,
+ }
+
+ let mut t = Trivia::default();
+
+ t.hm.insert(1, vec![0u8; 2048]);
+
+ assert!(t.malloc_size_of() > 2000);
+}
+
+#[test]
+#[cfg(feature = "std")]
+fn derive_ignore() {
+ #[derive(MallocSizeOf, Default)]
+ struct Trivia {
+ hm: std::collections::HashMap>,
+ #[ignore_malloc_size_of = "I don't like vectors"]
+ v: Vec,
+ }
+
+ let mut t = Trivia::default();
+
+ t.hm.insert(1, vec![0u8; 2048]);
+ t.v = vec![0u8; 1024];
+
+ assert!(t.malloc_size_of() < 3000);
+}