configurable jump table cache size
This commit is contained in:
parent
745a50dfdf
commit
8a0e98d4cc
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -295,7 +295,7 @@ dependencies = [
|
|||||||
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
|
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
|
||||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lru-cache 0.0.7 (git+https://github.com/contain-rs/lru-cache)",
|
||||||
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -881,7 +881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
version = "0.0.9"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -897,9 +897,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "lru-cache"
|
name = "lru-cache"
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/contain-rs/lru-cache#13255e33c45ceb69a4b143f235a4322df5fb580e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1950,10 +1950,10 @@ dependencies = [
|
|||||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||||
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
||||||
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
|
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
|
||||||
"checksum linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f7ff3baae999fdf921cccf54b61842bb3b26868d50d02dff48052ebec8dd79"
|
"checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48"
|
||||||
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
||||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||||
"checksum lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "42d50dcb5d9f145df83b1043207e1ac0c37c9c779c4e128ca4655abc3f3cbf8c"
|
"checksum lru-cache 0.0.7 (git+https://github.com/contain-rs/lru-cache)" = "<none>"
|
||||||
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
|
"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
|
||||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||||
"checksum mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74cc2587bf97c49f3f5bab62860d6abf3902ca73b66b51d9b049fbdcd727bd2"
|
"checksum mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74cc2587bf97c49f3f5bab62860d6abf3902ca73b66b51d9b049fbdcd727bd2"
|
||||||
|
@ -37,7 +37,7 @@ ethkey = { path = "../ethkey" }
|
|||||||
ethcore-ipc-nano = { path = "../ipc/nano" }
|
ethcore-ipc-nano = { path = "../ipc/nano" }
|
||||||
rlp = { path = "../util/rlp" }
|
rlp = { path = "../util/rlp" }
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
lru-cache = "0.0.7"
|
lru-cache = { git = "https://github.com/contain-rs/lru-cache" }
|
||||||
ethcore-bloom-journal = { path = "../util/bloom" }
|
ethcore-bloom-journal = { path = "../util/bloom" }
|
||||||
byteorder = "0.5"
|
byteorder = "0.5"
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ impl Client {
|
|||||||
let awake = match config.mode { Mode::Dark(..) => false, _ => true };
|
let awake = match config.mode { Mode::Dark(..) => false, _ => true };
|
||||||
|
|
||||||
let factories = Factories {
|
let factories = Factories {
|
||||||
vm: EvmFactory::new(config.vm_type.clone()),
|
vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size),
|
||||||
trie: TrieFactory::new(trie_spec),
|
trie: TrieFactory::new(trie_spec),
|
||||||
accountdb: Default::default(),
|
accountdb: Default::default(),
|
||||||
};
|
};
|
||||||
|
@ -108,6 +108,8 @@ pub struct ClientConfig {
|
|||||||
pub verifier_type: VerifierType,
|
pub verifier_type: VerifierType,
|
||||||
/// State db cache-size.
|
/// State db cache-size.
|
||||||
pub state_cache_size: usize,
|
pub state_cache_size: usize,
|
||||||
|
/// EVM jump-tables cache size.
|
||||||
|
pub jump_table_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -122,7 +122,7 @@ impl TestBlockChainClient {
|
|||||||
queue_size: AtomicUsize::new(0),
|
queue_size: AtomicUsize::new(0),
|
||||||
miner: Arc::new(Miner::with_spec(&spec)),
|
miner: Arc::new(Miner::with_spec(&spec)),
|
||||||
spec: spec,
|
spec: spec,
|
||||||
vm_factory: EvmFactory::new(VMType::Interpreter),
|
vm_factory: EvmFactory::new(VMType::Interpreter, 1024 * 1024),
|
||||||
latest_block_timestamp: RwLock::new(10_000_000),
|
latest_block_timestamp: RwLock::new(10_000_000),
|
||||||
};
|
};
|
||||||
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
|
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
|
||||||
|
@ -118,11 +118,12 @@ impl Factory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create new instance of specific `VMType` factory
|
/// Create new instance of specific `VMType` factory, with a size in bytes
|
||||||
pub fn new(evm: VMType) -> Self {
|
/// for caching jump destinations.
|
||||||
|
pub fn new(evm: VMType, cache_size: usize) -> Self {
|
||||||
Factory {
|
Factory {
|
||||||
evm: evm,
|
evm: evm,
|
||||||
evm_cache: Arc::new(SharedCache::default()),
|
evm_cache: Arc::new(SharedCache::new(cache_size)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,22 +165,22 @@ macro_rules! evm_test(
|
|||||||
#[ignore]
|
#[ignore]
|
||||||
#[cfg(feature = "jit")]
|
#[cfg(feature = "jit")]
|
||||||
fn $name_jit() {
|
fn $name_jit() {
|
||||||
$name_test(Factory::new(VMType::Jit));
|
$name_test(Factory::new(VMType::Jit, 1024 * 32));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn $name_int() {
|
fn $name_int() {
|
||||||
$name_test(Factory::new(VMType::Interpreter));
|
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($name_test: ident: $name_jit: ident, $name_int: ident) => {
|
($name_test: ident: $name_jit: ident, $name_int: ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "jit")]
|
#[cfg(feature = "jit")]
|
||||||
fn $name_jit() {
|
fn $name_jit() {
|
||||||
$name_test(Factory::new(VMType::Jit));
|
$name_test(Factory::new(VMType::Jit, 1024 * 32));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn $name_int() {
|
fn $name_int() {
|
||||||
$name_test(Factory::new(VMType::Interpreter));
|
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -193,13 +194,13 @@ macro_rules! evm_test_ignore(
|
|||||||
#[cfg(feature = "jit")]
|
#[cfg(feature = "jit")]
|
||||||
#[cfg(feature = "ignored-tests")]
|
#[cfg(feature = "ignored-tests")]
|
||||||
fn $name_jit() {
|
fn $name_jit() {
|
||||||
$name_test(Factory::new(VMType::Jit));
|
$name_test(Factory::new(VMType::Jit, 1024 * 32));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[cfg(feature = "ignored-tests")]
|
#[cfg(feature = "ignored-tests")]
|
||||||
fn $name_int() {
|
fn $name_int() {
|
||||||
$name_test(Factory::new(VMType::Interpreter));
|
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -21,25 +21,66 @@ use util::sha3::*;
|
|||||||
use bit_set::BitSet;
|
use bit_set::BitSet;
|
||||||
use super::super::instructions;
|
use super::super::instructions;
|
||||||
|
|
||||||
const CACHE_CODE_ITEMS: usize = 4096;
|
const INITIAL_CAPACITY: usize = 32;
|
||||||
|
const DEFAULT_CACHE_SIZE: usize = 4 * 1024 * 1024;
|
||||||
|
|
||||||
/// Global cache for EVM interpreter
|
/// Global cache for EVM interpreter
|
||||||
pub struct SharedCache {
|
pub struct SharedCache {
|
||||||
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>
|
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>,
|
||||||
|
max_size: usize,
|
||||||
|
cur_size: Mutex<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedCache {
|
impl SharedCache {
|
||||||
|
/// Create a jump destinations cache with a maximum size in bytes
|
||||||
|
/// to cache.
|
||||||
|
pub fn new(max_size: usize) -> Self {
|
||||||
|
SharedCache {
|
||||||
|
jump_destinations: Mutex::new(LruCache::new(INITIAL_CAPACITY)),
|
||||||
|
max_size: max_size * 8, // dealing with bits here.
|
||||||
|
cur_size: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get jump destinations bitmap for a contract.
|
/// Get jump destinations bitmap for a contract.
|
||||||
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
|
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
|
||||||
if code_hash == &SHA3_EMPTY {
|
if code_hash == &SHA3_EMPTY {
|
||||||
return Self::find_jump_destinations(code);
|
return Self::find_jump_destinations(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
|
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
|
||||||
return d.clone();
|
return d.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let d = Self::find_jump_destinations(code);
|
let d = Self::find_jump_destinations(code);
|
||||||
self.jump_destinations.lock().insert(code_hash.clone(), d.clone());
|
|
||||||
|
{
|
||||||
|
let mut cur_size = self.cur_size.lock();
|
||||||
|
*cur_size += d.capacity();
|
||||||
|
|
||||||
|
let mut jump_dests = self.jump_destinations.lock();
|
||||||
|
let cap = jump_dests.capacity();
|
||||||
|
|
||||||
|
// grow the cache as necessary; it operates on amount of items
|
||||||
|
// but we're working based on memory usage.
|
||||||
|
if jump_dests.len() == cap && *cur_size < self.max_size {
|
||||||
|
jump_dests.set_capacity(cap * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// account for any element displaced from the cache.
|
||||||
|
if let Some(lru) = jump_dests.insert(code_hash.clone(), d.clone()) {
|
||||||
|
*cur_size -= lru.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove elements until we are below the memory target.
|
||||||
|
while *cur_size > self.max_size {
|
||||||
|
match jump_dests.remove_lru() {
|
||||||
|
Some((_, v)) => *cur_size -= v.capacity(),
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d
|
d
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,15 +98,15 @@ impl SharedCache {
|
|||||||
}
|
}
|
||||||
position += 1;
|
position += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jump_dests.shrink_to_fit();
|
||||||
Arc::new(jump_dests)
|
Arc::new(jump_dests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SharedCache {
|
impl Default for SharedCache {
|
||||||
fn default() -> SharedCache {
|
fn default() -> Self {
|
||||||
SharedCache {
|
SharedCache::new(DEFAULT_CACHE_SIZE)
|
||||||
jump_destinations: Mutex::new(LruCache::new(CACHE_CODE_ITEMS)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,7 +817,7 @@ fn test_signextend(factory: super::Factory) {
|
|||||||
|
|
||||||
#[test] // JIT just returns out of gas
|
#[test] // JIT just returns out of gas
|
||||||
fn test_badinstruction_int() {
|
fn test_badinstruction_int() {
|
||||||
let factory = super::Factory::new(VMType::Interpreter);
|
let factory = super::Factory::new(VMType::Interpreter, 1024 * 32);
|
||||||
let code = "af".from_hex().unwrap();
|
let code = "af".from_hex().unwrap();
|
||||||
|
|
||||||
let mut params = ActionParams::default();
|
let mut params = ActionParams::default();
|
||||||
|
@ -598,7 +598,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
// Tracing is not suported in JIT
|
// Tracing is not suported in JIT
|
||||||
fn test_call_to_create() {
|
fn test_call_to_create() {
|
||||||
let factory = Factory::new(VMType::Interpreter);
|
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
|
||||||
|
|
||||||
// code:
|
// code:
|
||||||
//
|
//
|
||||||
@ -724,7 +724,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_create_contract() {
|
fn test_create_contract() {
|
||||||
// Tracing is not supported in JIT
|
// Tracing is not supported in JIT
|
||||||
let factory = Factory::new(VMType::Interpreter);
|
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
|
||||||
// code:
|
// code:
|
||||||
//
|
//
|
||||||
// 60 10 - push 16
|
// 60 10 - push 16
|
||||||
|
@ -95,7 +95,12 @@ impl CacheConfig {
|
|||||||
|
|
||||||
/// Size of the state cache.
|
/// Size of the state cache.
|
||||||
pub fn state(&self) -> u32 {
|
pub fn state(&self) -> u32 {
|
||||||
self.state
|
self.state * 3 / 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Size of the jump-tables cache.
|
||||||
|
pub fn jump_tables(&self) -> u32 {
|
||||||
|
self.state / 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +114,8 @@ mod tests {
|
|||||||
assert_eq!(config.db, 140);
|
assert_eq!(config.db, 140);
|
||||||
assert_eq!(config.blockchain(), 20);
|
assert_eq!(config.blockchain(), 20);
|
||||||
assert_eq!(config.queue(), 50);
|
assert_eq!(config.queue(), 50);
|
||||||
assert_eq!(config.state(), 40);
|
assert_eq!(config.state(), 30);
|
||||||
|
assert_eq!(config.jump_tables(), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -215,7 +215,10 @@ pub fn to_client_config(
|
|||||||
client_config.tracing.max_cache_size = cache_config.traces() as usize * mb;
|
client_config.tracing.max_cache_size = cache_config.traces() as usize * mb;
|
||||||
// in bytes
|
// in bytes
|
||||||
client_config.tracing.pref_cache_size = cache_config.traces() as usize * 3 / 4 * mb;
|
client_config.tracing.pref_cache_size = cache_config.traces() as usize * 3 / 4 * mb;
|
||||||
client_config.state_cache_size = cache_config.state() as usize;
|
// in bytes
|
||||||
|
client_config.state_cache_size = cache_config.state() as usize * mb;
|
||||||
|
// in bytes
|
||||||
|
client_config.jump_table_size = cache_config.jump_tables() as usize * mb;
|
||||||
|
|
||||||
client_config.mode = mode;
|
client_config.mode = mode;
|
||||||
client_config.tracing.enabled = tracing;
|
client_config.tracing.enabled = tracing;
|
||||||
|
Loading…
Reference in New Issue
Block a user