From 4cb9d4519f1993fe40471ef85cdb9c325ad1fc30 Mon Sep 17 00:00:00 2001 From: victork Date: Tue, 15 Jul 2025 13:45:36 +0300 Subject: [PATCH] starknet_api: using internal implementation of sizeof --- Cargo.lock | 7 + Cargo.toml | 2 + crates/sizeof/sizeof_internal/Cargo.toml | 13 ++ crates/sizeof/sizeof_internal/src/lib.rs | 207 +++++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 crates/sizeof/sizeof_internal/Cargo.toml create mode 100644 crates/sizeof/sizeof_internal/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1df943a0185..a946d60d191 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11844,6 +11844,13 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "sizeof_internal" +version = "0.15.0-rc.2" +dependencies = [ + "starknet-types-core", +] + [[package]] name = "sketches-ddsketch" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 1c71b31e607..40d019a8ae7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ members = [ "crates/papyrus_monitoring_gateway", "crates/papyrus_node", "crates/shared_execution_objects", + "crates/sizeof/sizeof_internal", "crates/starknet_api", "crates/starknet_committer", "crates/starknet_committer_and_os_cli", @@ -282,6 +283,7 @@ sha3 = "0.10.8" shared_execution_objects.path = "crates/shared_execution_objects" simple_logger = "4.0.0" size-of = "0.1.5" +sizeof_internal = { path = "crates/sizeof/sizeof_internal" } socket2 = "0.5.8" starknet-core = "0.12.1" starknet-crypto = "0.7.1" diff --git a/crates/sizeof/sizeof_internal/Cargo.toml b/crates/sizeof/sizeof_internal/Cargo.toml new file mode 100644 index 00000000000..699ee42989d --- /dev/null +++ b/crates/sizeof/sizeof_internal/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sizeof_internal" +version.workspace = true +edition.workspace = true +repository.workspace = true +license-file.workspace = true +description = "compute size of types in memory" + +[lints] +workspace = true + +[dependencies] +starknet-types-core.workspace = true diff --git a/crates/sizeof/sizeof_internal/src/lib.rs b/crates/sizeof/sizeof_internal/src/lib.rs new file mode 100644 index 00000000000..de6e619fb6b --- /dev/null +++ b/crates/sizeof/sizeof_internal/src/lib.rs @@ -0,0 +1,207 @@ +use std::ops::Deref; +use std::rc::Rc; +use std::sync::Arc; + +use starknet_types_core::felt::Felt; + +/// Trait for types that can report their size in bytes. +/// There are two methods: +/// - `dynamic_size`: returns the size of the heap part of the type. +/// - `size_bytes`: returns the total size of the type, including both stack and heap parts. +/// +/// This trait is useful for calculating the size of types in memory, especially when dealing with +/// dynamic data structures like `Vec` or `String`. +pub trait SizeOf { + /// Returns the heap size of the type in bytes. + /// + /// `WARNING`: It is `DANGEROUS` to use this function on types that implement `Deref`, since + /// `Deref coercion` will neglect counting the stack size taken by the original type + /// itself. Currently, this trait is only implemented for the following `Deref` types: + /// `Box, Rc, Arc`. If your `Deref` type is not on this list, refrain from using + /// this method. + fn dynamic_size(&self) -> usize; + + /// Returns the total size of the type in bytes, including both stack and heap parts. + /// + /// `WARNING`: It is `DANGEROUS` to use this function on types that implement `Deref`, since + /// `Deref coercion` will neglect counting the stack size taken by the original type + /// itself. Currently, this trait is only implemented for the following `Deref` types: + /// `Box, Rc, Arc`. If your `Deref` type is not on this list, refrain from using + /// this method. + fn size_bytes(&self) -> usize + where + Self: Sized, + { + std::mem::size_of::() + self.dynamic_size() + } +} + +#[macro_export] +macro_rules! default_primitive_sizeof { + ($($type:ty),*) => { + $( + impl SizeOf for $type { + fn dynamic_size(&self) -> usize { + 0 + } + } + )* + }; +} + +default_primitive_sizeof! { + bool, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, + f32, f64, + usize, isize, + Felt +} + +impl SizeOf for String { + fn dynamic_size(&self) -> usize { + self.capacity() + } +} + +impl SizeOf for Vec { + fn dynamic_size(&self) -> usize { + let used = self.iter().map(|x| x.size_bytes()).sum::(); + let excess = (self.capacity() - self.len()) * std::mem::size_of::(); + + used + excess + } +} + +#[macro_export] +macro_rules! default_deref_sizeof { + ($($name:ident < $($generic_params:ident $(: $bounds:path)*),* >),*) => { + $( + impl < $($generic_params : $crate::SizeOf $(+ $bounds)* ),* > $crate::SizeOf for $name < $($generic_params),* > { + fn dynamic_size(&self) -> usize { + self.deref().size_bytes() + } + } + )* + }; +} + +default_deref_sizeof! { Box, Rc, Arc } + +#[test] +fn test_size_of() { + assert_eq!(17_u8.size_bytes(), 1); + assert_eq!( + String::from("Hello").size_bytes(), + std::mem::size_of::() + String::from("Hello").capacity() + ); + assert_eq!( + vec![1_u8, 2_u8, 3_u8].size_bytes(), + std::mem::size_of::>() + std::mem::size_of::() * 3 + ); +} + +#[test] +fn test_felt_size_of() { + assert_eq!(Felt::ZERO.size_bytes(), 32); + assert_eq!(Felt::ONE.size_bytes(), 32); + assert_eq!(Felt::from(1600000000).size_bytes(), 32); + assert_eq!(Felt::MAX.size_bytes(), 32); +} + +#[test] +fn test_vec_string_sizeof() { + let mut vec_string = Vec::with_capacity(17); + vec_string.push(String::from("Hello")); + vec_string.push(String::from("World!")); + let size = vec_string.size_bytes(); + assert_eq!( + size, + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + ); + assert_eq!(vec_string[0].size_bytes(), std::mem::size_of::() + 5); + assert_eq!(vec_string[1].size_bytes(), std::mem::size_of::() + 6); +} + +#[test] +fn test_arc_vec_string_sizeof() { + let mut vec_string = Vec::with_capacity(35); + vec_string.push(String::from("Starknet")); + vec_string.push(String::from("Cairo")); + + let vec_string = Arc::new(vec_string); + + let size = vec_string.size_bytes(); + assert_eq!( + size, + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + + std::mem::size_of::>>() + ); + assert_eq!( + vec_string.deref().size_bytes(), + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + ); + assert_eq!(vec_string[0].size_bytes(), std::mem::size_of::() + 8); + assert_eq!(vec_string[1].size_bytes(), std::mem::size_of::() + 5); +} + +#[test] +fn test_rc_vec_string_sizeof() { + let mut vec_string = Vec::with_capacity(25); + vec_string.push(String::from("Pip")); + vec_string.push(String::from("Install")); + + let vec_string = Rc::new(vec_string); + + let size = vec_string.size_bytes(); + assert_eq!( + size, + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + + std::mem::size_of::>>() + ); + assert_eq!( + vec_string.deref().size_bytes(), + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + ); + assert_eq!(vec_string[0].size_bytes(), std::mem::size_of::() + 3); + assert_eq!(vec_string[1].size_bytes(), std::mem::size_of::() + 7); +} + +#[test] +fn test_box_vec_string_sizeof() { + let mut vec_string = Vec::with_capacity(20); + vec_string.push(String::from("Rust")); + vec_string.push(String::from("Programming")); + let vec_string = Box::new(vec_string); + let size = vec_string.size_bytes(); + assert_eq!( + size, + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + + std::mem::size_of::>>() + ); + assert_eq!( + vec_string.deref().size_bytes(), + vec_string[0].size_bytes() + + vec_string[1].size_bytes() + + (vec_string.capacity() - vec_string.len()) * std::mem::size_of::() + + std::mem::size_of::>() + ); + assert_eq!(vec_string[0].size_bytes(), std::mem::size_of::() + 4); + assert_eq!(vec_string[1].size_bytes(), std::mem::size_of::() + 11); +}