Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Merge pull request #2516 from ethcore/canon-cache-size
Browse files Browse the repository at this point in the history
Mostly configurable canonical cache size
  • Loading branch information
rphmeier authored Oct 12, 2016
2 parents c9ce25c + 4276ab8 commit 4bcc9e3
Show file tree
Hide file tree
Showing 19 changed files with 243 additions and 145 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ ethkey = { path = "../ethkey" }
ethcore-ipc-nano = { path = "../ipc/nano" }
rlp = { path = "../util/rlp" }
rand = "0.3"
lru-cache = "0.0.7"
lru-cache = { git = "https://github.com/contain-rs/lru-cache" }
ethcore-bloom-journal = { path = "../util/bloom" }
byteorder = "0.5"

Expand Down
7 changes: 4 additions & 3 deletions ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl Client {
};

let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE);
let mut state_db = StateDB::new(journal_db);
let mut state_db = StateDB::new(journal_db, config.state_cache_size);
if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db)) {
let mut batch = DBTransaction::new(&db);
try!(state_db.commit(&mut batch, 0, &spec.genesis_header().hash(), None));
Expand All @@ -190,7 +190,7 @@ impl Client {
let awake = match config.mode { Mode::Dark(..) => false, _ => true };

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),
accountdb: Default::default(),
};
Expand Down Expand Up @@ -682,7 +682,8 @@ impl snapshot::DatabaseRestore for Client {
let db = self.db.write();
try!(db.restore(new_db));

*state_db = StateDB::new(journaldb::new(db.clone(), self.pruning, ::db::COL_STATE));
let cache_size = state_db.cache_size();
*state_db = StateDB::new(journaldb::new(db.clone(), self.pruning, ::db::COL_STATE), cache_size);
*chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone()));
*tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone());
Ok(())
Expand Down
6 changes: 5 additions & 1 deletion ethcore/src/client/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub struct ClientConfig {
pub pruning: journaldb::Algorithm,
/// The name of the client instance.
pub name: String,
/// State db cache-size if not default
/// RocksDB state column cache-size if not default
pub db_cache_size: Option<usize>,
/// State db compaction profile
pub db_compaction: DatabaseCompactionProfile,
Expand All @@ -106,6 +106,10 @@ pub struct ClientConfig {
pub mode: Mode,
/// Type of block verifier used by client.
pub verifier_type: VerifierType,
/// State db cache-size.
pub state_cache_size: usize,
/// EVM jump-tables cache size.
pub jump_table_size: usize,
}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl TestBlockChainClient {
queue_size: AtomicUsize::new(0),
miner: Arc::new(Miner::with_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),
};
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
Expand Down Expand Up @@ -298,7 +298,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
let temp = RandomTempPath::new();
let db = Database::open(&DatabaseConfig::with_columns(NUM_COLUMNS), temp.as_str()).unwrap();
let journal_db = journaldb::new(Arc::new(db), journaldb::Algorithm::EarlyMerge, COL_STATE);
let state_db = StateDB::new(journal_db);
let state_db = StateDB::new(journal_db, 1024 * 1024);
GuardedTempResult {
_temp: temp,
result: Some(state_db)
Expand Down
19 changes: 10 additions & 9 deletions ethcore/src/evm/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ impl Factory {
}
}

/// Create new instance of specific `VMType` factory
pub fn new(evm: VMType) -> Self {
/// Create new instance of specific `VMType` factory, with a size in bytes
/// for caching jump destinations.
pub fn new(evm: VMType, cache_size: usize) -> Self {
Factory {
evm: evm,
evm_cache: Arc::new(SharedCache::default()),
evm_cache: Arc::new(SharedCache::new(cache_size)),
}
}

Expand Down Expand Up @@ -164,22 +165,22 @@ macro_rules! evm_test(
#[ignore]
#[cfg(feature = "jit")]
fn $name_jit() {
$name_test(Factory::new(VMType::Jit));
$name_test(Factory::new(VMType::Jit, 1024 * 32));
}
#[test]
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) => {
#[test]
#[cfg(feature = "jit")]
fn $name_jit() {
$name_test(Factory::new(VMType::Jit));
$name_test(Factory::new(VMType::Jit, 1024 * 32));
}
#[test]
fn $name_int() {
$name_test(Factory::new(VMType::Interpreter));
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
}
}
);
Expand All @@ -193,13 +194,13 @@ macro_rules! evm_test_ignore(
#[cfg(feature = "jit")]
#[cfg(feature = "ignored-tests")]
fn $name_jit() {
$name_test(Factory::new(VMType::Jit));
$name_test(Factory::new(VMType::Jit, 1024 * 32));
}
#[test]
#[ignore]
#[cfg(feature = "ignored-tests")]
fn $name_int() {
$name_test(Factory::new(VMType::Interpreter));
$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
}
}
);
59 changes: 50 additions & 9 deletions ethcore/src/evm/interpreter/shared_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,66 @@ use util::sha3::*;
use bit_set::BitSet;
use super::super::instructions;

const CACHE_CODE_ITEMS: usize = 65536;
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 {
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>
jump_destinations: Mutex<LruCache<H256, Arc<BitSet>>>,
max_size: usize,
cur_size: Mutex<usize>,
}

impl SharedCache {
/// Get jump destincations bitmap for a contract.
/// 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.
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
if code_hash == &SHA3_EMPTY {
return Self::find_jump_destinations(code);
}

if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
return d.clone();
}

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
}

Expand All @@ -57,15 +98,15 @@ impl SharedCache {
}
position += 1;
}

jump_dests.shrink_to_fit();
Arc::new(jump_dests)
}
}

impl Default for SharedCache {
fn default() -> SharedCache {
SharedCache {
jump_destinations: Mutex::new(LruCache::new(CACHE_CODE_ITEMS)),
}
fn default() -> Self {
SharedCache::new(DEFAULT_CACHE_SIZE)
}
}

Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/evm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ fn test_signextend(factory: super::Factory) {

#[test] // JIT just returns out of gas
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 mut params = ActionParams::default();
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ mod tests {
#[test]
// Tracing is not suported in JIT
fn test_call_to_create() {
let factory = Factory::new(VMType::Interpreter);
let factory = Factory::new(VMType::Interpreter, 1024 * 32);

// code:
//
Expand Down Expand Up @@ -724,7 +724,7 @@ mod tests {
#[test]
fn test_create_contract() {
// Tracing is not supported in JIT
let factory = Factory::new(VMType::Interpreter);
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
// code:
//
// 60 10 - push 16
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/json_tests/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
state.populate_from(From::from(vm.pre_state.clone()));
let info = From::from(vm.env);
let engine = TestEngine::new(1);
let vm_factory = Factory::new(vm_type.clone());
let vm_factory = Factory::new(vm_type.clone(), 1024 * 32);
let params = ActionParams::from(vm.transaction);

let mut substate = Substate::new();
Expand Down
Loading

0 comments on commit 4bcc9e3

Please sign in to comment.