From 54924d14b3cdcbad31df975f7f76b587ed77ef51 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Feb 2016 01:59:14 +0100 Subject: [PATCH] Include JSONRPC CLI options. Bump version numbers. Update Trie benchmarks. Disable RLP benchmark (@debrid please fix). --- ethcore/Cargo.toml | 2 +- ethcore/src/blockchain.rs | 74 +++++++++++++++++++--------------- ethcore/src/client.rs | 7 +++- parity/main.rs | 23 +++++++---- util/Cargo.toml | 4 +- util/benches/rlp.rs | 3 +- util/benches/trie.rs | 78 ++++++++++++++++++++++++++++++++++++ util/src/trie/standardmap.rs | 24 ++++++++--- 8 files changed, 166 insertions(+), 49 deletions(-) diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 35fa5df81..6b7a69a68 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore library" homepage = "http://ethcore.io" license = "GPL-3.0" name = "ethcore" -version = "0.1.0" +version = "0.9.0" authors = ["Ethcore "] [dependencies] diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 757e51c59..1dea65ae7 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -129,6 +129,9 @@ struct CacheManager { /// /// **Does not do input data verification.** pub struct BlockChain { + pref_cache_size: usize, + max_cache_size: usize, + best_block: RwLock, // block cache @@ -190,9 +193,7 @@ impl BlockProvider for BlockChain { } } -const COLLECTION_QUEUE_SIZE: usize = 2; -const MIN_CACHE_SIZE: usize = 1; -const MAX_CACHE_SIZE: usize = 1024 * 1024; +const COLLECTION_QUEUE_SIZE: usize = 8; impl BlockChain { /// Create new instance of blockchain from given Genesis @@ -237,6 +238,8 @@ impl BlockChain { (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); let bc = BlockChain { + pref_cache_size: 1 << 14, + max_cache_size: 1 << 20, best_block: RwLock::new(BestBlock::new()), blocks: RwLock::new(HashMap::new()), block_details: RwLock::new(HashMap::new()), @@ -288,6 +291,12 @@ impl BlockChain { bc } + /// Set the cache configuration. + pub fn configure_cache(&mut self, pref_cache_size: usize, max_cache_size: usize) { + self.pref_cache_size = pref_cache_size; + self.max_cache_size = max_cache_size; + } + /// Returns a tree route between `from` and `to`, which is a tuple of: /// /// - a vector of hashes of all blocks, ordered from `from` to `to`. @@ -339,12 +348,12 @@ impl BlockChain { Some(h) => h, None => return None, }; - Some(self._tree_route((&from_details, &from), (&to_details, &to))) + Some(self.tree_route_aux((&from_details, &from), (&to_details, &to))) } /// Similar to `tree_route` function, but can be used to return a route /// between blocks which may not be in database yet. - fn _tree_route(&self, from: (&BlockDetails, &H256), to: (&BlockDetails, &H256)) -> TreeRoute { + fn tree_route_aux(&self, from: (&BlockDetails, &H256), to: (&BlockDetails, &H256)) -> TreeRoute { let mut from_branch = vec![]; let mut to_branch = vec![]; @@ -465,7 +474,7 @@ impl BlockChain { // find the route between old best block and the new one let best_hash = self.best_block_hash(); let best_details = self.block_details(&best_hash).expect("best block hash is invalid!"); - let route = self._tree_route((&best_details, &best_hash), (&details, &hash)); + let route = self.tree_route_aux((&best_details, &best_hash), (&details, &hash)); match route.blocks.len() { // its our parent @@ -581,36 +590,37 @@ impl BlockChain { } /// Ticks our cache system and throws out any old data. - pub fn collect_garbage(&self, force: bool) { - // TODO: check time. - let timeout = true; + pub fn collect_garbage(&self) { + if self.cache_size().total() < self.pref_cache_size { return; } - let t = self.cache_size().total(); - if t < MIN_CACHE_SIZE || (!timeout && (!force || t < MAX_CACHE_SIZE)) { return; } + for _ in 0..COLLECTION_QUEUE_SIZE { + { + let mut cache_man = self.cache_man.write().unwrap(); + let mut blocks = self.blocks.write().unwrap(); + let mut block_details = self.block_details.write().unwrap(); + let mut block_hashes = self.block_hashes.write().unwrap(); + let mut transaction_addresses = self.transaction_addresses.write().unwrap(); + let mut block_logs = self.block_logs.write().unwrap(); + let mut blocks_blooms = self.blocks_blooms.write().unwrap(); - let mut cache_man = self.cache_man.write().unwrap(); - let mut blocks = self.blocks.write().unwrap(); - let mut block_details = self.block_details.write().unwrap(); - let mut block_hashes = self.block_hashes.write().unwrap(); - let mut transaction_addresses = self.transaction_addresses.write().unwrap(); - let mut block_logs = self.block_logs.write().unwrap(); - let mut blocks_blooms = self.blocks_blooms.write().unwrap(); + for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { + cache_man.in_use.remove(&id); + match id { + CacheID::Block(h) => { blocks.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlockDetails, h) => { block_details.remove(&h); }, + CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); }, + _ => panic!(), + } + } + cache_man.cache_usage.push_front(HashSet::new()); - for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { - cache_man.in_use.remove(&id); - match id { - CacheID::Block(h) => { blocks.remove(&h); }, - CacheID::Extras(ExtrasIndex::BlockDetails, h) => { block_details.remove(&h); }, - CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); }, - CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); }, - CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); }, - _ => panic!(), + // TODO: handle block_hashes properly. + block_hashes.clear(); } + if self.cache_size().total() < self.max_cache_size { break; } } - cache_man.cache_usage.push_front(HashSet::new()); - - // TODO: handle block_hashes properly. - block_hashes.clear(); // TODO: m_lastCollection = chrono::system_clock::now(); } @@ -786,7 +796,7 @@ mod tests { assert!(bc.cache_size().blocks > 1024 * 1024); for _ in 0..2 { - bc.collect_garbage(true); + bc.collect_garbage(); } assert!(bc.cache_size().blocks < 1024 * 1024); } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 1a59aefc5..ee9b658d8 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -294,7 +294,12 @@ impl Client { /// Tick the client. pub fn tick(&self) { - self.chain.read().unwrap().collect_garbage(false); + self.chain.read().unwrap().collect_garbage(); + } + + /// Set up the cache behaviour. + pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { + self.chain.write().unwrap().configure_cache(pref_cache_size, max_cache_size); } } diff --git a/parity/main.rs b/parity/main.rs index a9dfe004e..6aec14884 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -35,9 +35,15 @@ Usage: parity [options] ... Options: - -l --logging LOGGING Specify the logging level - -h --help Show this screen. -"); + -l --logging LOGGING Specify the logging level. + -j --jsonrpc Enable the JSON-RPC API sever. + --jsonrpc-url URL Specify URL for JSON-RPC API server (default: 127.0.0.1:8545). + + --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes (default: 16384). + --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes (default: 262144). + + -h --help Show this screen. +", flag_cache_pref_size: usize, flag_cache_max_size: usize); fn setup_log(init: &str) { let mut builder = LogBuilder::new(); @@ -54,7 +60,7 @@ fn setup_log(init: &str) { #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc) { +fn setup_rpc_server(client: Arc, sync: Arc, url: &str) { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); @@ -62,11 +68,11 @@ fn setup_rpc_server(client: Arc, sync: Arc) { server.add_delegate(EthClient::new(client.clone()).to_delegate()); server.add_delegate(EthFilterClient::new(client).to_delegate()); server.add_delegate(NetClient::new(sync).to_delegate()); - server.start_async("127.0.0.1:3030"); + server.start_async(url); } #[cfg(not(feature = "rpc"))] -fn setup_rpc_server(_client: Arc, _sync: Arc) { +fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { } fn main() { @@ -83,8 +89,11 @@ fn main() { net_settings.boot_nodes = init_nodes; let mut service = ClientService::start(spec, net_settings).unwrap(); let client = service.client().clone(); + client.configure_cache(args.flag_cache_pref_size, args.flag_cache_max_size); let sync = EthSync::register(service.network(), client); - setup_rpc_server(service.client(), sync.clone()); + if args.flag_jsonrpc { + setup_rpc_server(service.client(), sync.clone(), &args.flag_jsonrpc_url); + } let io_handler = Arc::new(ClientIoHandler { client: service.client(), info: Default::default(), sync: sync }); service.io().register_handler(io_handler).expect("Error registering IO handler"); diff --git a/util/Cargo.toml b/util/Cargo.toml index 3c70df8d6..a123aecca 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore utility library" homepage = "http://ethcore.io" license = "GPL-3.0" name = "ethcore-util" -version = "0.1.0" +version = "0.9.0" authors = ["Ethcore "] [dependencies] @@ -28,4 +28,4 @@ sha3 = { path = "sha3" } serde = "0.6.7" clippy = "0.0.37" json-tests = { path = "json-tests" } -target_info = "0.1.0" \ No newline at end of file +target_info = "0.1.0" diff --git a/util/benches/rlp.rs b/util/benches/rlp.rs index 8bc7599e4..234f7c66d 100644 --- a/util/benches/rlp.rs +++ b/util/benches/rlp.rs @@ -3,7 +3,7 @@ //! ```bash //! multirust run nightly cargo bench //! ``` - +/* #![feature(test)] extern crate test; @@ -94,3 +94,4 @@ fn bench_stream_1000_empty_lists(b: &mut Bencher) { let _ = stream.out(); }); } +*/ \ No newline at end of file diff --git a/util/benches/trie.rs b/util/benches/trie.rs index 5f02b15cf..663663fe3 100644 --- a/util/benches/trie.rs +++ b/util/benches/trie.rs @@ -42,6 +42,84 @@ fn random_value(seed: &mut H256) -> Bytes { } } +#[bench] +fn trie_insertions_32_mir_1k(b: &mut Bencher) { + let st = StandardMap { + alphabet: Alphabet::All, + min_key: 32, + journal_key: 0, + value_mode: ValueMode::Mirror, + count: 1000, + }; + let d = st.make(); + let mut hash_count = 0usize; + b.iter(&mut ||{ + let mut memdb = MemoryDB::new(); + let mut root = H256::new(); + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for i in d.iter() { + t.insert(&i.0, &i.1); + } + hash_count = t.hash_count; + }); +// println!("hash_count: {}", hash_count); +} + +#[bench] +fn triehash_insertions_32_mir_1k(b: &mut Bencher) { + let st = StandardMap { + alphabet: Alphabet::All, + min_key: 32, + journal_key: 0, + value_mode: ValueMode::Mirror, + count: 1000, + }; + let d = st.make(); + b.iter(&mut ||{ + trie_root(d.clone()).clone(); + }); +} + +#[bench] +fn trie_insertions_32_ran_1k(b: &mut Bencher) { + let st = StandardMap { + alphabet: Alphabet::All, + min_key: 32, + journal_key: 0, + value_mode: ValueMode::Random, + count: 1000, + }; + let d = st.make(); + let mut hash_count = 0usize; + let mut r = H256::new(); + b.iter(&mut ||{ + let mut memdb = MemoryDB::new(); + let mut root = H256::new(); + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for i in d.iter() { + t.insert(&i.0, &i.1); + } + hash_count = t.hash_count; + r = t.root().clone(); + }); +// println!("result: {}", hash_count); +} + +#[bench] +fn triehash_insertions_32_ran_1k(b: &mut Bencher) { + let st = StandardMap { + alphabet: Alphabet::All, + min_key: 32, + journal_key: 0, + value_mode: ValueMode::Random, + count: 1000, + }; + let d = st.make(); + b.iter(&mut ||{ + trie_root(d.clone()).clone(); + }); +} + #[bench] fn trie_insertions_six_high(b: &mut Bencher) { let mut d: Vec<(Bytes, Bytes)> = Vec::new(); diff --git a/util/src/trie/standardmap.rs b/util/src/trie/standardmap.rs index 0e65849cc..4573efd66 100644 --- a/util/src/trie/standardmap.rs +++ b/util/src/trie/standardmap.rs @@ -17,12 +17,26 @@ pub enum Alphabet { Custom(Bytes), } +/// Means of determining the value. +pub enum ValueMode { + /// Same as the key. + Mirror, + /// Randomly (50:50) 1 or 32 byte randomly string. + Random, +} + /// Standard test map for profiling tries. pub struct StandardMap { - alphabet: Alphabet, - min_key: usize, - journal_key: usize, - count: usize, + /// The alphabet to use for keys. + pub alphabet: Alphabet, + /// Minimum size of key. + pub min_key: usize, + /// Delta size of key. + pub journal_key: usize, + /// Mode of value generation. + pub value_mode: ValueMode, + /// Number of keys. + pub count: usize, } impl StandardMap { @@ -71,7 +85,7 @@ impl StandardMap { Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed), Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, &mut seed), }; - let v = Self::random_value(&mut seed); + let v = match self.value_mode { ValueMode::Mirror => k.clone(), ValueMode::Random => Self::random_value(&mut seed) }; d.push((k, v)) } d