Skip to content

Commit

Permalink
feat: cache weight allocated size (#161)
Browse files Browse the repository at this point in the history
* calculate cache module & script allocated size

* calculate cache module & script allocated size

* delete unused libraries

* delete deps

* delete storage testing

* rollback shared libraries

* refactory PR161 (#163)

* add debug assert to sure no case to call get_size recursively

* ignore cache insertion error to avoid non-deterministic state

* fmt

* fix lint

---------

Co-authored-by: beer-1 <[email protected]>
Co-authored-by: beer-1 <[email protected]>
  • Loading branch information
3 people authored Nov 1, 2024
1 parent 02d65ec commit 3b79790
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 188 deletions.
1 change: 0 additions & 1 deletion crates/e2e-move-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,5 @@ default = []
testing = [
"initia-move-gas/testing",
"initia-move-natives/testing",
"initia-move-storage/testing",
"move-vm-runtime/testing",
]
7 changes: 2 additions & 5 deletions crates/storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,5 @@ parking_lot = { workspace = true }
sha3 = { workspace = true }
claims = { workspace = true }

[features]
default = []
testing = [
"move-vm-runtime/testing",
]
[dev-dependencies]
rand = { workspace = true }
84 changes: 84 additions & 0 deletions crates/storage/src/allocator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::{
alloc::{GlobalAlloc, Layout, System},
cell::Cell,
};

use move_binary_format::errors::VMResult;

thread_local! {
static METERING: Cell<bool> = const { Cell::new(false) };
static SIZE: Cell<usize> = const { Cell::new(0) };
}

struct SizeCounterAllocator;

unsafe impl GlobalAlloc for SizeCounterAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if METERING.with(|metering| metering.get()) {
SIZE.with(|size| size.set(size.get() + layout.size()));
}

System.alloc(layout)
}

unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
System.dealloc(ptr, layout)
}
}

#[global_allocator]
static GLOBAL: SizeCounterAllocator = SizeCounterAllocator;

#[inline]
fn start_metering() {
debug_assert!(!METERING.with(|metering| metering.get()));
SIZE.with(|size| size.set(0));
METERING.with(|metering| metering.set(true));
}

#[inline]
fn finish_metering() -> usize {
debug_assert!(METERING.with(|metering| metering.get()));
METERING.with(|metering| metering.set(false));
SIZE.with(|size| size.get())
}

#[inline]
pub(crate) fn get_size<T, O: FnOnce() -> VMResult<T>>(f: O) -> VMResult<(T, usize)> {
start_metering();
let ret = f()?;
let size = finish_metering();

Ok((ret, size + size_of::<T>()))
}

#[cfg(test)]
mod allocator_test {
use rand::Rng;
use std::thread;

use super::*;

#[test]
fn test_get_size() {
let num_thread = 100;
for _ in 0..num_thread {
let handle = thread::spawn(|| {
let num_bytes = rand::thread_rng().gen_range(0..5120); // < 5KB
let (_, size) = get_size(|| {
for _ in 0..num_bytes {
// allocate 1 byte
let _ = vec![0u8; 1];
}

Ok(())
})
.unwrap();

assert_eq!(size, num_bytes);
});

handle.join().unwrap();
}
}
}
51 changes: 36 additions & 15 deletions crates/storage/src/code_scale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,45 @@ use crate::module_cache::BytesWithHash;
use crate::module_cache::NoVersion;
use crate::state_view::Checksum;

pub struct CodeScale;
pub struct ScriptScale;

impl WeightScale<Checksum, Code<CompiledScript, Script>> for CodeScale {
fn weight(&self, _key: &Checksum, _value: &Code<CompiledScript, Script>) -> usize {
1
impl WeightScale<Checksum, ScriptWrapper> for ScriptScale {
fn weight(&self, _key: &Checksum, value: &ScriptWrapper) -> usize {
value.size
}
}

pub struct ModuleCodeScale;

impl WeightScale<Checksum, Arc<ModuleCode<CompiledModule, Module, BytesWithHash, NoVersion>>>
for ModuleCodeScale
{
fn weight(
&self,
_key: &Checksum,
_value: &Arc<ModuleCode<CompiledModule, Module, BytesWithHash, NoVersion>>,
) -> usize {
1
pub struct ModuleScale;

impl WeightScale<Checksum, ModuleWrapper> for ModuleScale {
fn weight(&self, _key: &Checksum, value: &ModuleWrapper) -> usize {
value.size
}
}

#[derive(Clone)]
pub struct ScriptWrapper {
pub code: Code<CompiledScript, Script>,
pub size: usize,
}

impl ScriptWrapper {
pub fn new(code: Code<CompiledScript, Script>, size: usize) -> Self {
Self { code, size }
}
}

#[derive(Clone)]
pub struct ModuleWrapper {
pub module_code: Arc<ModuleCode<CompiledModule, Module, BytesWithHash, NoVersion>>,
pub size: usize,
}

impl ModuleWrapper {
pub fn new(
module_code: Arc<ModuleCode<CompiledModule, Module, BytesWithHash, NoVersion>>,
size: usize,
) -> Self {
Self { module_code, size }
}
}
71 changes: 44 additions & 27 deletions crates/storage/src/code_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ use move_vm_runtime::{
logging::expect_no_verification_errors, CodeStorage, Module, ModuleStorage, RuntimeEnvironment,
Script, WithRuntimeEnvironment,
};
use move_vm_types::{
code::{Code, ModuleBytesStorage},
module_linker_error, sha3_256,
};
use move_vm_types::{code::ModuleBytesStorage, module_linker_error, sha3_256};
use std::sync::Arc;

use crate::{
allocator::get_size,
module_cache::InitiaModuleCache,
module_storage::{AsInitiaModuleStorage, InitiaModuleStorage},
script_cache::InitiaScriptCache,
Expand Down Expand Up @@ -98,29 +96,41 @@ impl<M: ModuleStorage> CodeStorage for InitiaCodeStorage<M> {
) -> VMResult<Arc<CompiledScript>> {
let hash = sha3_256(serialized_script);
Ok(match self.script_cache.get_script(&hash) {
Some(script) => script.deserialized().clone(),
Some(script) => script.code.deserialized().clone(),
None => {
let deserialized_script = self
.runtime_environment()
.deserialize_into_script(serialized_script)?;
self.script_cache
.insert_deserialized_script(hash, deserialized_script)?
// Deserialize the script and compute its size.
let (deserialized_script, allocated_size) = get_size(move || {
self.runtime_environment()
.deserialize_into_script(serialized_script)
})?;

// Cache the deserialized script.
self.script_cache.insert_deserialized_script(
hash,
deserialized_script,
allocated_size,
)?
}
})
}

fn verify_and_cache_script(&self, serialized_script: &[u8]) -> VMResult<Arc<Script>> {
use Code::*;

let hash = sha3_256(serialized_script);
let deserialized_script = match self.script_cache.get_script(&hash) {
Some(Verified(script)) => return Ok(script),
Some(Deserialized(deserialized_script)) => deserialized_script,
None => self
.runtime_environment()
.deserialize_into_script(serialized_script)
.map(Arc::new)?,
};
let (deserialized_script, compiled_script_allocated_size) =
match self.script_cache.get_script(&hash) {
Some(code_wrapper) => {
if code_wrapper.code.is_verified() {
return Ok(code_wrapper.code.verified().clone());
}

(code_wrapper.code.deserialized().clone(), code_wrapper.size)
}
None => get_size(move || {
self.runtime_environment()
.deserialize_into_script(serialized_script)
.map(Arc::new)
})?,
};

// Locally verify the script.
let locally_verified_script = self
Expand All @@ -137,12 +147,19 @@ impl<M: ModuleStorage> CodeStorage for InitiaCodeStorage<M> {
.ok_or_else(|| module_linker_error!(addr, name))
})
.collect::<VMResult<Vec<_>>>()?;
let verified_script = self
.runtime_environment()
.build_verified_script(locally_verified_script, &immediate_dependencies)?;

self.script_cache
.insert_verified_script(hash, verified_script)
// Verify the script and compute its size.
let (verified_script, allocated_size) = get_size(move || {
self.runtime_environment()
.build_verified_script(locally_verified_script, &immediate_dependencies)
})?;

// Cache the verified script.
self.script_cache.insert_verified_script(
hash,
verified_script,
allocated_size + compiled_script_allocated_size,
)
}
}

Expand All @@ -162,11 +179,11 @@ impl<M: ModuleStorage> InitiaCodeStorage<M> {
);
for hash in deserialized {
let script = claims::assert_some!(self.script_cache.get_script(hash));
assert!(!script.is_verified())
assert!(!script.code.is_verified())
}
for hash in verified {
let script = claims::assert_some!(self.script_cache.get_script(hash));
assert!(script.is_verified())
assert!(script.code.is_verified())
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ pub mod module_cache;
pub mod module_storage;
pub mod script_cache;

mod allocator;
pub mod code_scale;
Loading

0 comments on commit 3b79790

Please sign in to comment.