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

Mostly configurable canonical cache size #2516

Merged
merged 5 commits into from
Oct 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -177,7 +177,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 @@ -197,7 +197,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 @@ -694,7 +694,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 @@ -122,7 +122,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 @@ -289,7 +289,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.
Copy link
Collaborator

@arkpar arkpar Oct 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be better to create an a type of LRUCache that manages that and reuse it for the state cache as well. E.g LRUHeapSizeCache that requires HeapSizeOf. Can be done in a future PR though

Copy link
Contributor Author

@rphmeier rphmeier Oct 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might make an upstream PR to implement that. Contributing back to the community and all :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've filed an issue at contain-rs/lru-cache#38, I intend to implement and incorporate to the follow-up PR where we'll want this in more than one place.

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