cache internals

This commit is contained in:
Svyatoslav Nikolsky
2017-06-28 11:03:01 +03:00
parent 7803faaa74
commit aad4dfa67e
4 changed files with 92 additions and 26 deletions

54
benches/interpreter.rs Normal file
View 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)
}

View File

@ -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.

View File

@ -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;

View File

@ -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(),