Add hidden flag --cache-key to use prehashed modules for speed

This commit is contained in:
Mark McCaskey
2019-07-08 15:46:28 -07:00
parent 2fa58097c2
commit 4407a7cf93
3 changed files with 75 additions and 27 deletions

View File

@ -5,8 +5,10 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments. Blocks of changes will separated by version increments.
## **[Unreleased]** ## **[Unreleased]**
## 0.5.4 - [#537](https://github.com/wasmerio/wasmer/pull/537) Add hidden flag (`--cache-key`) to use prehashed key into the compiled wasm cache
- [#536](https://github.com/wasmerio/wasmer/pull/536) Update cache to use compiler backend name in cache key - [#536](https://github.com/wasmerio/wasmer/pull/536) Update cache to use compiler backend name in cache key
## 0.5.4
- [#529](https://github.com/wasmerio/wasmer/pull/529) Updates the Wasm Interface library, which is used by wapm, with bug fixes and error message improvements - [#529](https://github.com/wasmerio/wasmer/pull/529) Updates the Wasm Interface library, which is used by wapm, with bug fixes and error message improvements
## 0.5.3 ## 0.5.3

View File

@ -77,6 +77,30 @@ impl WasmHash {
hex::encode(&self.into_array() as &[u8]) hex::encode(&self.into_array() as &[u8])
} }
/// Create hash from hexadecimal representation
pub fn decode(hex_str: &str) -> Result<Self, Error> {
let bytes = hex::decode(hex_str).map_err(|e| {
Error::DeserializeError(format!(
"Could not decode prehashed key as hexadecimal: {}",
e
))
})?;
if bytes.len() != 64 {
return Err(Error::DeserializeError(
"Prehashed keys must deserialze into exactly 64 bytes".to_string(),
));
}
use std::convert::TryInto;
Ok(WasmHash(
bytes[0..32].try_into().map_err(|e| {
Error::DeserializeError(format!("Could not get first 32 bytes: {}", e))
})?,
bytes[32..64].try_into().map_err(|e| {
Error::DeserializeError(format!("Could not get last 32 bytes: {}", e))
})?,
))
}
pub(crate) fn into_array(self) -> [u8; 64] { pub(crate) fn into_array(self) -> [u8; 64] {
let mut total = [0u8; 64]; let mut total = [0u8; 64];
total[0..32].copy_from_slice(&self.0); total[0..32].copy_from_slice(&self.0);

View File

@ -24,6 +24,7 @@ use wasmer_runtime::{
use wasmer_runtime_core::{ use wasmer_runtime_core::{
self, self,
backend::{Backend, Compiler, CompilerConfig, MemoryBoundCheckMode}, backend::{Backend, Compiler, CompilerConfig, MemoryBoundCheckMode},
debug,
loader::{Instance as LoadedInstance, LocalLoader}, loader::{Instance as LoadedInstance, LocalLoader},
}; };
#[cfg(feature = "backend:singlepass")] #[cfg(feature = "backend:singlepass")]
@ -115,9 +116,18 @@ struct Run {
#[structopt(long = "resume")] #[structopt(long = "resume")]
resume: Option<String>, resume: Option<String>,
/// The command name is a string that will override the first argument passed
/// to the wasm program. This is used in wapm to provide nicer output in
/// help commands and error messages of the running wasm program
#[structopt(long = "command-name", hidden = true)] #[structopt(long = "command-name", hidden = true)]
command_name: Option<String>, command_name: Option<String>,
/// A prehashed string, used to speed up start times by avoiding hashing the
/// wasm module. If the specified hash is not found, Wasmer will hash the module
/// as if no `cache-key` argument was passed.
#[structopt(long = "cache-key", hidden = true)]
cache_key: Option<String>,
/// Application arguments /// Application arguments
#[structopt(name = "--", raw(multiple = "true"))] #[structopt(name = "--", raw(multiple = "true"))]
args: Vec<String>, args: Vec<String>,
@ -350,10 +360,6 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
} else { } else {
// If we have cache enabled // If we have cache enabled
// We generate a hash for the given binary, so we can use it as key
// for the Filesystem cache
let hash = WasmHash::generate_for_backend(&wasm_binary, options.backend);
let wasmer_cache_dir = get_cache_dir(); let wasmer_cache_dir = get_cache_dir();
// We create a new cache instance. // We create a new cache instance.
@ -362,31 +368,47 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
let mut cache = unsafe { let mut cache = unsafe {
FileSystemCache::new(wasmer_cache_dir).map_err(|e| format!("Cache error: {:?}", e))? FileSystemCache::new(wasmer_cache_dir).map_err(|e| format!("Cache error: {:?}", e))?
}; };
let load_cache_key = || -> Result<_, String> {
// cache.load will return the Module if it's able to deserialize it properly, and an error if: if let Some(ref prehashed_cache_key) = options.cache_key {
// * The file is not found if let Ok(module) = WasmHash::decode(prehashed_cache_key)
// * The file exists, but it's corrupted or can't be converted to a module .and_then(|prehashed_key| cache.load(prehashed_key))
match cache.load(hash) { {
Ok(module) => { debug!("using prehashed key: {}", prehashed_cache_key);
// We are able to load the module from cache return Ok(module);
module }
} }
Err(_) => {
let module = webassembly::compile_with_config_with(
&wasm_binary[..],
CompilerConfig {
symbol_map: em_symbol_map,
..Default::default()
},
&*compiler,
)
.map_err(|e| format!("Can't compile module: {:?}", e))?;
// We try to save the module into a cache file
cache.store(hash, module.clone()).unwrap_or_default();
module // We generate a hash for the given binary, so we can use it as key
// for the Filesystem cache
let hash = WasmHash::generate_for_backend(&wasm_binary, options.backend);
// cache.load will return the Module if it's able to deserialize it properly, and an error if:
// * The file is not found
// * The file exists, but it's corrupted or can't be converted to a module
match cache.load(hash) {
Ok(module) => {
// We are able to load the module from cache
Ok(module)
}
Err(_) => {
let module = webassembly::compile_with_config_with(
&wasm_binary[..],
CompilerConfig {
symbol_map: em_symbol_map,
..Default::default()
},
&*compiler,
)
.map_err(|e| format!("Can't compile module: {:?}", e))?;
// We try to save the module into a cache file
cache.store(hash, module.clone()).unwrap_or_default();
Ok(module)
}
} }
} };
load_cache_key()?
}; };
if let Some(loader) = options.loader { if let Some(loader) = options.loader {