-
Notifications
You must be signed in to change notification settings - Fork 11
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
refactor: reinstate module cache #106
Conversation
#[cfg(not(test))] | ||
/// one hundred giga ops | ||
pub const WASM_METERING_LIMIT: u64 = 100_000_000_000; | ||
|
||
#[cfg(test)] | ||
/// ten mega ops. | ||
/// We don't want tests to run forever, and it can take several minutes for 100 giga ops to run. | ||
pub const WASM_METERING_LIMIT: u64 = 10_000_000; | ||
|
||
/// Generate an engine with a wasm compiler | ||
/// and Metering (use limits) in place. | ||
pub fn make_compiler_engine() -> Engine { | ||
let cost_function = |_operator: &wasmparser::Operator| -> u64 { 1 }; | ||
// @todo 100 giga-ops is totally arbitrary cutoff so we probably | ||
// want to make the limit configurable somehow. | ||
let metering = Arc::new(Metering::new(WASM_METERING_LIMIT, cost_function)); | ||
// the only place where the wasm compiler engine is set | ||
let mut compiler = Cranelift::default(); | ||
compiler.canonicalize_nans(true).push_middleware(metering); | ||
Engine::from(compiler) | ||
} | ||
|
||
/// Generate a runtime `Engine` without compiler suitable for iOS. | ||
/// Useful for re-building an iOS Module from a preserialized WASM Module. | ||
pub fn make_ios_runtime_engine() -> Engine { | ||
Engine::headless() | ||
} | ||
|
||
/// Take WASM binary and prepare a wasmer Module suitable for iOS | ||
pub fn build_ios_module(wasm: &[u8]) -> Result<Module, CompileError> { | ||
info!( | ||
"Found wasm and was instructed to serialize it for ios in wasmer format, doing so now..." | ||
); | ||
let compiler_engine = make_compiler_engine(); | ||
let store = Store::new(compiler_engine); | ||
Module::from_binary(&store, wasm) | ||
} | ||
|
||
/// Deserialize a previously compiled module for iOS from a file. | ||
pub fn get_ios_module_from_file(path: &PathBuf) -> Result<Module, DeserializeError> { | ||
let engine = make_ios_runtime_engine(); | ||
unsafe { Module::deserialize_from_file(&engine, path) } | ||
} | ||
|
||
/// Configuration of a Target for wasmer for iOS | ||
pub fn wasmer_ios_target() -> Target { | ||
// use what I see in | ||
// platform ios headless example | ||
// https://github.com/wasmerio/wasmer/blob/447c2e3a152438db67be9ef649327fabcad6f5b8/examples/platform_ios_headless.rs#L38-L53 | ||
let triple = Triple::from_str("aarch64-apple-ios").unwrap(); | ||
let cpu_feature = CpuFeature::set(); | ||
Target::new(triple, cpu_feature) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these items come from holochain_types::wasmer_types
@@ -128,7 +192,12 @@ pub struct SerializedModuleCache { | |||
pub plru: MicroCache, | |||
pub key_map: PlruKeyMap, | |||
pub cache: BTreeMap<CacheKey, Arc<SerializedModule>>, | |||
pub cranelift: fn() -> Cranelift, | |||
// a function to create a new compiler engine for every module | |||
pub make_compiler_engine: fn() -> Engine, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To keep this independent of the compiler, I changed it return an engine
pub fn default_with_cranelift(cranelift: fn() -> Cranelift) -> Self { | ||
/// Build a default `SerializedModuleCache` with a fn to create an `Engine` | ||
/// that will be used to compile modules from wasms as needed. | ||
pub fn default_with_engine( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arguably this can be renamed to new_with_engine
or just new
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable to me, is this a breaking change anyway? If so I'd go for the rename. Otherwise maybe leave a comment behind to do it later?
// wasm_module, | ||
// wasm_instance, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently the bench fails because such numerous deserialization of modules causes memory leaks because of an upstream issue where the memory for deserialization is kept as long as the engine lives wasmerio/wasmer#4377 (comment)
This shouldn't affect Holochain in practice because we're only deserializing every module once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can a note be left in the code here so we don't have to trace back to this PR to figure out why these are commented out later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, have left a few comments but nothing that really concerns me so I'll approve and leave them with you :)
@@ -1,3 +1,5 @@ | |||
[workspace] | |||
members = ["crates/host", "crates/common"] | |||
exclude = ["test"] | |||
|
|||
resolver = "2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Makes debugging feature problems so much easier
|
||
/// Generate a runtime `Engine` without compiler suitable for iOS. | ||
/// Useful for re-building an iOS Module from a preserialized WASM Module. | ||
pub fn make_ios_runtime_engine() -> Engine { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be behind a platform flag so they aren't available everywhere? Or are they valid anywhere but just recommended for iOS?
Actually I think even in the second case, if they have ios in the name I'd be in favour of them being behind a platform condition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They haven't been behind a feature flag before inside holochain
, I just ported these over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood, I still think they probably ought to be but as this was just moved code it can wait for a less busy time :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another limiting factor is that where they're used in holochain
is in an if..else
assignment, so I think we can't hide a part of it behind a feature. https://github.com/holochain/holochain/pull/3152/files#diff-14f820cc8b4334c432a642d67c2e4de0fb36249b4dd73b8bf6124482abc45427R350-R356
pub fn default_with_cranelift(cranelift: fn() -> Cranelift) -> Self { | ||
/// Build a default `SerializedModuleCache` with a fn to create an `Engine` | ||
/// that will be used to compile modules from wasms as needed. | ||
pub fn default_with_engine( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable to me, is this a breaking change anyway? If so I'd go for the rename. Otherwise maybe leave a comment behind to do it later?
(deserialized_module, serialized_module) | ||
} | ||
// no serialized module found on the file system, so serialize the | ||
// wasm binary and write it to the file system | ||
_fs_miss => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is a file system miss the only option here? What about other errors in a Some(Err(_))
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is existing code, just checking while we're here and looking at it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case of a Some(Err) the err will be swallowed, something to improve I agree
crates/host/src/module.rs
Outdated
} | ||
|
||
#[test] | ||
fn cache_test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these tests be in a module that is only available in test config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, YAY tests! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh okay, again this is an existing pattern for this create. Understood, something for another time!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ThetaSinner @jost-s uh no? there are tests in the test
folder, why is this here? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thedavidmeister To have access to the member fields. If I put the test in the tests
folder, I need to make the member fields public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jost-s ah, so then can we put it behind a cfg?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thedavidmeister done
// wasm_module, | ||
// wasm_instance, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can a note be left in the code here so we don't have to trace back to this PR to figure out why these are commented out later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only thing is i'm not sure why there are tests in the main crates rather than test crates
crates/host/src/module.rs
Outdated
} | ||
|
||
#[test] | ||
fn cache_test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ThetaSinner @jost-s uh no? there are tests in the test
folder, why is this here? 😅
Instance cache in host crate has been removed in favor of a deserialized module cache
DeserializedModuleCache
. An abstraction for caching (serialized & deserialized modules) calledModuleCache
was added.All logic related to modules and wasmer caching from
holochain
has been moved to the host crate. Consequently functions for wasmer development under iOS need to be imported from here.