mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-20 18:26:54 +00:00
cache internals
This commit is contained in:
54
benches/interpreter.rs
Normal file
54
benches/interpreter.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
extern crate parity_wasm;
|
||||||
|
|
||||||
|
use test::Bencher;
|
||||||
|
use parity_wasm::builder::module;
|
||||||
|
use parity_wasm::elements::{ExportEntry, Internal, ImportEntry, External, Opcodes, Opcode};
|
||||||
|
use parity_wasm::interpreter::{ProgramInstance, ModuleInstanceInterface, RuntimeValue};
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn export_entry_performance(b: &mut Bencher) {
|
||||||
|
// create module with 1000 functions
|
||||||
|
const NUM_FUNCTIONS: u32 = 1000;
|
||||||
|
let mut callee_module = module();
|
||||||
|
for i in 0..NUM_FUNCTIONS {
|
||||||
|
callee_module = callee_module
|
||||||
|
.with_export(ExportEntry::new(format!("func{}", i), Internal::Function(i)))
|
||||||
|
.function()
|
||||||
|
.signature().return_type().i32().build()
|
||||||
|
.body().with_opcodes(Opcodes::new(vec![
|
||||||
|
Opcode::I32Const(i as i32),
|
||||||
|
Opcode::End,
|
||||||
|
])).build()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
let callee_module = callee_module.build();
|
||||||
|
|
||||||
|
// create module which call one of 1000 functions
|
||||||
|
let caller_module = module()
|
||||||
|
.with_import(ImportEntry::new("callee_module".into(), "func500".into(), External::Function(0)))
|
||||||
|
.function()
|
||||||
|
.signature().return_type().i32().build()
|
||||||
|
.body().with_opcodes(Opcodes::new(vec![
|
||||||
|
Opcode::Call(0),
|
||||||
|
Opcode::I32Const(1000),
|
||||||
|
Opcode::I32Add,
|
||||||
|
Opcode::End,
|
||||||
|
])).build()
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// add both modules to program
|
||||||
|
let program = ProgramInstance::new().unwrap();
|
||||||
|
program.add_module("callee_module", callee_module, None).unwrap();
|
||||||
|
let caller_module = program.add_module("caller_module", caller_module, None).unwrap();
|
||||||
|
|
||||||
|
// run bench
|
||||||
|
b.iter(||
|
||||||
|
assert_eq!(caller_module.execute_index(1, vec![].into()).unwrap(), Some(RuntimeValue::I32(1500)))
|
||||||
|
);
|
||||||
|
|
||||||
|
// test export_entry_performance ... bench: 3,497 ns/iter (+/- 200)
|
||||||
|
}
|
@ -8,7 +8,6 @@ use interpreter::program::ProgramInstanceEssence;
|
|||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::variable::{VariableInstance, VariableType};
|
use interpreter::variable::{VariableInstance, VariableType};
|
||||||
|
|
||||||
// TODO: cache Internal-s to fasten access
|
|
||||||
/// Module imports.
|
/// Module imports.
|
||||||
pub struct ModuleImports {
|
pub struct ModuleImports {
|
||||||
/// Program instance.
|
/// Program instance.
|
||||||
|
@ -74,7 +74,7 @@ mod variable;
|
|||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub use self::memory::MemoryInstance;
|
pub use self::memory::MemoryInstance;
|
||||||
pub use self::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, ExportEntryType, CallerContext, ExecutionParams};
|
pub use self::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
|
||||||
pub use self::table::TableInstance;
|
pub use self::table::TableInstance;
|
||||||
pub use self::program::ProgramInstance;
|
pub use self::program::ProgramInstance;
|
||||||
pub use self::value::RuntimeValue;
|
pub use self::value::RuntimeValue;
|
||||||
|
@ -98,6 +98,8 @@ pub struct ModuleInstance {
|
|||||||
functions_labels: HashMap<u32, HashMap<usize, usize>>,
|
functions_labels: HashMap<u32, HashMap<usize, usize>>,
|
||||||
/// Module imports.
|
/// Module imports.
|
||||||
imports: ModuleImports,
|
imports: ModuleImports,
|
||||||
|
/// Module exports.
|
||||||
|
exports: HashMap<String, Vec<Internal>>,
|
||||||
/// Tables.
|
/// Tables.
|
||||||
tables: Vec<Arc<TableInstance>>,
|
tables: Vec<Arc<TableInstance>>,
|
||||||
/// Linear memory regions.
|
/// Linear memory regions.
|
||||||
@ -211,6 +213,7 @@ impl ModuleInstance {
|
|||||||
name: name,
|
name: name,
|
||||||
module: module,
|
module: module,
|
||||||
imports: imports,
|
imports: imports,
|
||||||
|
exports: HashMap::new(),
|
||||||
functions_labels: HashMap::new(),
|
functions_labels: HashMap::new(),
|
||||||
memory: memory,
|
memory: memory,
|
||||||
tables: tables,
|
tables: tables,
|
||||||
@ -236,19 +239,27 @@ impl ModuleInstance {
|
|||||||
if let Some(export_section) = self.module.export_section() {
|
if let Some(export_section) = self.module.export_section() {
|
||||||
for export in export_section.entries() {
|
for export in export_section.entries() {
|
||||||
match export.internal() {
|
match export.internal() {
|
||||||
&Internal::Function(function_index) =>
|
&Internal::Function(function_index) => {
|
||||||
self.require_function(ItemIndex::IndexSpace(function_index)).map(|_| ())?,
|
self.require_function(ItemIndex::IndexSpace(function_index)).map(|_| ())?;
|
||||||
&Internal::Global(global_index) =>
|
self.exports.entry(export.field().into()).or_insert_with(Default::default).push(Internal::Function(function_index));
|
||||||
|
},
|
||||||
|
&Internal::Global(global_index) => {
|
||||||
self.global(ItemIndex::IndexSpace(global_index), None)
|
self.global(ItemIndex::IndexSpace(global_index), None)
|
||||||
.and_then(|g| if g.is_mutable() {
|
.and_then(|g| if g.is_mutable() {
|
||||||
Err(Error::Validation(format!("trying to export mutable global {}", export.field())))
|
Err(Error::Validation(format!("trying to export mutable global {}", export.field())))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?,
|
})?;
|
||||||
&Internal::Memory(memory_index) =>
|
self.exports.entry(export.field().into()).or_insert_with(Default::default).push(Internal::Global(global_index));
|
||||||
self.memory(ItemIndex::IndexSpace(memory_index)).map(|_| ())?,
|
},
|
||||||
&Internal::Table(table_index) =>
|
&Internal::Memory(memory_index) => {
|
||||||
self.table(ItemIndex::IndexSpace(table_index)).map(|_| ())?,
|
self.memory(ItemIndex::IndexSpace(memory_index)).map(|_| ())?;
|
||||||
|
self.exports.entry(export.field().into()).or_insert_with(Default::default).push(Internal::Memory(memory_index));
|
||||||
|
},
|
||||||
|
&Internal::Table(table_index) => {
|
||||||
|
self.table(ItemIndex::IndexSpace(table_index)).map(|_| ())?;
|
||||||
|
self.exports.entry(export.field().into()).or_insert_with(Default::default).push(Internal::Table(table_index));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,15 +433,15 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
|
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let index = self.module.export_section()
|
let index = self.exports.get(name)
|
||||||
.ok_or(Error::Function("missing export section".into()))
|
.ok_or(Error::Function(format!("missing exports with name {}", name)))
|
||||||
.and_then(|s| s.entries().iter()
|
.and_then(|l| l.iter()
|
||||||
.find(|e| e.field() == name && match e.internal() {
|
.find(|i| match i {
|
||||||
&Internal::Function(_) => true,
|
&&Internal::Function(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.ok_or(Error::Function(format!("missing export section exported function with name {}", name)))
|
.ok_or(Error::Function(format!("missing exported function with name {}", name)))
|
||||||
.map(|e| match e.internal() {
|
.map(|i| match i {
|
||||||
&Internal::Function(index) => index,
|
&Internal::Function(index) => index,
|
||||||
_ => unreachable!(), // checked couple of lines above
|
_ => unreachable!(), // checked couple of lines above
|
||||||
})
|
})
|
||||||
@ -439,24 +450,24 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
|
fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
|
||||||
self.module.export_section()
|
self.exports.get(name)
|
||||||
.ok_or(Error::Program(format!("trying to import {} from module without export section", name)))
|
.ok_or(Error::Function(format!("missing exports with name {}", name)))
|
||||||
.and_then(|s| s.entries().iter()
|
.and_then(|l| l.iter()
|
||||||
.find(|e| e.field() == name && match required_type {
|
.find(|i| match required_type {
|
||||||
&ExportEntryType::Any => true,
|
&ExportEntryType::Any => true,
|
||||||
&ExportEntryType::Global(global_type) => match e.internal() {
|
&ExportEntryType::Global(global_type) => match i {
|
||||||
&Internal::Global(global_index) => self.global(ItemIndex::IndexSpace(global_index), Some(global_type)).map(|_| true).unwrap_or(false),
|
&&Internal::Global(global_index) => self.global(ItemIndex::IndexSpace(global_index), Some(global_type)).map(|_| true).unwrap_or(false),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
&ExportEntryType::Function(ref required_type) => match e.internal() {
|
&ExportEntryType::Function(ref required_type) => match i {
|
||||||
&Internal::Function(function_index) =>
|
&&Internal::Function(function_index) =>
|
||||||
self.function_type(ItemIndex::IndexSpace(function_index))
|
self.function_type(ItemIndex::IndexSpace(function_index))
|
||||||
.map(|ft| ft == *required_type)
|
.map(|ft| ft == *required_type)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.map(|e| *e.internal())
|
.map(|i| *i)
|
||||||
.ok_or(Error::Program(format!("unresolved import {}", name))))
|
.ok_or(Error::Program(format!("unresolved import {}", name))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,6 +664,7 @@ fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, ex
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FunctionSignature<'a> {
|
impl<'a> FunctionSignature<'a> {
|
||||||
|
/// Get return type of this function.
|
||||||
pub fn return_type(&self) -> Option<ValueType> {
|
pub fn return_type(&self) -> Option<ValueType> {
|
||||||
match self {
|
match self {
|
||||||
&FunctionSignature::Module(ft) => ft.return_type(),
|
&FunctionSignature::Module(ft) => ft.return_type(),
|
||||||
@ -660,6 +672,7 @@ impl<'a> FunctionSignature<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get parameters of this function.
|
||||||
pub fn params(&self) -> &[ValueType] {
|
pub fn params(&self) -> &[ValueType] {
|
||||||
match self {
|
match self {
|
||||||
&FunctionSignature::Module(ft) => ft.params(),
|
&FunctionSignature::Module(ft) => ft.params(),
|
||||||
|
Reference in New Issue
Block a user