Merge branch 'master' into travis_fixes

This commit is contained in:
debris 2016-02-02 02:37:43 +01:00
commit 21913b29b5
8 changed files with 166 additions and 49 deletions

View File

@ -3,7 +3,7 @@ description = "Ethcore library"
homepage = "http://ethcore.io" homepage = "http://ethcore.io"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore" name = "ethcore"
version = "0.1.0" version = "0.9.0"
authors = ["Ethcore <admin@ethcore.io>"] authors = ["Ethcore <admin@ethcore.io>"]
[dependencies] [dependencies]

View File

@ -129,6 +129,9 @@ struct CacheManager {
/// ///
/// **Does not do input data verification.** /// **Does not do input data verification.**
pub struct BlockChain { pub struct BlockChain {
pref_cache_size: usize,
max_cache_size: usize,
best_block: RwLock<BestBlock>, best_block: RwLock<BestBlock>,
// block cache // block cache
@ -190,9 +193,7 @@ impl BlockProvider for BlockChain {
} }
} }
const COLLECTION_QUEUE_SIZE: usize = 2; const COLLECTION_QUEUE_SIZE: usize = 8;
const MIN_CACHE_SIZE: usize = 1;
const MAX_CACHE_SIZE: usize = 1024 * 1024;
impl BlockChain { impl BlockChain {
/// Create new instance of blockchain from given Genesis /// 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())); (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new()));
let bc = BlockChain { let bc = BlockChain {
pref_cache_size: 1 << 14,
max_cache_size: 1 << 20,
best_block: RwLock::new(BestBlock::new()), best_block: RwLock::new(BestBlock::new()),
blocks: RwLock::new(HashMap::new()), blocks: RwLock::new(HashMap::new()),
block_details: RwLock::new(HashMap::new()), block_details: RwLock::new(HashMap::new()),
@ -288,6 +291,12 @@ impl BlockChain {
bc 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: /// 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`. /// - a vector of hashes of all blocks, ordered from `from` to `to`.
@ -339,12 +348,12 @@ impl BlockChain {
Some(h) => h, Some(h) => h,
None => return None, 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 /// Similar to `tree_route` function, but can be used to return a route
/// between blocks which may not be in database yet. /// 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 from_branch = vec![];
let mut to_branch = vec![]; let mut to_branch = vec![];
@ -465,7 +474,7 @@ impl BlockChain {
// find the route between old best block and the new one // find the route between old best block and the new one
let best_hash = self.best_block_hash(); let best_hash = self.best_block_hash();
let best_details = self.block_details(&best_hash).expect("best block hash is invalid!"); 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() { match route.blocks.len() {
// its our parent // its our parent
@ -581,36 +590,37 @@ impl BlockChain {
} }
/// Ticks our cache system and throws out any old data. /// Ticks our cache system and throws out any old data.
pub fn collect_garbage(&self, force: bool) { pub fn collect_garbage(&self) {
// TODO: check time. if self.cache_size().total() < self.pref_cache_size { return; }
let timeout = true;
let t = self.cache_size().total(); for _ in 0..COLLECTION_QUEUE_SIZE {
if t < MIN_CACHE_SIZE || (!timeout && (!force || t < MAX_CACHE_SIZE)) { return; } {
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(); for id in cache_man.cache_usage.pop_back().unwrap().into_iter() {
let mut blocks = self.blocks.write().unwrap(); cache_man.in_use.remove(&id);
let mut block_details = self.block_details.write().unwrap(); match id {
let mut block_hashes = self.block_hashes.write().unwrap(); CacheID::Block(h) => { blocks.remove(&h); },
let mut transaction_addresses = self.transaction_addresses.write().unwrap(); CacheID::Extras(ExtrasIndex::BlockDetails, h) => { block_details.remove(&h); },
let mut block_logs = self.block_logs.write().unwrap(); CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); },
let mut blocks_blooms = self.blocks_blooms.write().unwrap(); 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() { // TODO: handle block_hashes properly.
cache_man.in_use.remove(&id); block_hashes.clear();
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!(),
} }
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(); // TODO: m_lastCollection = chrono::system_clock::now();
} }
@ -786,7 +796,7 @@ mod tests {
assert!(bc.cache_size().blocks > 1024 * 1024); assert!(bc.cache_size().blocks > 1024 * 1024);
for _ in 0..2 { for _ in 0..2 {
bc.collect_garbage(true); bc.collect_garbage();
} }
assert!(bc.cache_size().blocks < 1024 * 1024); assert!(bc.cache_size().blocks < 1024 * 1024);
} }

View File

@ -294,7 +294,12 @@ impl Client {
/// Tick the client. /// Tick the client.
pub fn tick(&self) { 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);
} }
} }

View File

@ -35,9 +35,15 @@ Usage:
parity [options] <enode>... parity [options] <enode>...
Options: Options:
-l --logging LOGGING Specify the logging level -l --logging LOGGING Specify the logging level.
-h --help Show this screen. -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) { fn setup_log(init: &str) {
let mut builder = LogBuilder::new(); let mut builder = LogBuilder::new();
@ -54,7 +60,7 @@ fn setup_log(init: &str) {
#[cfg(feature = "rpc")] #[cfg(feature = "rpc")]
fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>) { fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str) {
use rpc::v1::*; use rpc::v1::*;
let mut server = rpc::HttpServer::new(1); let mut server = rpc::HttpServer::new(1);
@ -62,11 +68,11 @@ fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>) {
server.add_delegate(EthClient::new(client.clone()).to_delegate()); server.add_delegate(EthClient::new(client.clone()).to_delegate());
server.add_delegate(EthFilterClient::new(client).to_delegate()); server.add_delegate(EthFilterClient::new(client).to_delegate());
server.add_delegate(NetClient::new(sync).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"))] #[cfg(not(feature = "rpc"))]
fn setup_rpc_server(_client: Arc<Client>, _sync: Arc<EthSync>) { fn setup_rpc_server(_client: Arc<Client>, _sync: Arc<EthSync>, _url: &str) {
} }
fn main() { fn main() {
@ -83,8 +89,11 @@ fn main() {
net_settings.boot_nodes = init_nodes; net_settings.boot_nodes = init_nodes;
let mut service = ClientService::start(spec, net_settings).unwrap(); let mut service = ClientService::start(spec, net_settings).unwrap();
let client = service.client().clone(); 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); 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 }); 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"); service.io().register_handler(io_handler).expect("Error registering IO handler");

View File

@ -3,7 +3,7 @@ description = "Ethcore utility library"
homepage = "http://ethcore.io" homepage = "http://ethcore.io"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore-util" name = "ethcore-util"
version = "0.1.0" version = "0.9.0"
authors = ["Ethcore <admin@ethcore.io>"] authors = ["Ethcore <admin@ethcore.io>"]
[dependencies] [dependencies]
@ -28,4 +28,4 @@ sha3 = { path = "sha3" }
serde = "0.6.7" serde = "0.6.7"
clippy = "0.0.37" clippy = "0.0.37"
json-tests = { path = "json-tests" } json-tests = { path = "json-tests" }
target_info = "0.1.0" target_info = "0.1.0"

View File

@ -3,7 +3,7 @@
//! ```bash //! ```bash
//! multirust run nightly cargo bench //! multirust run nightly cargo bench
//! ``` //! ```
/*
#![feature(test)] #![feature(test)]
extern crate test; extern crate test;
@ -94,3 +94,4 @@ fn bench_stream_1000_empty_lists(b: &mut Bencher) {
let _ = stream.out(); let _ = stream.out();
}); });
} }
*/

View File

@ -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] #[bench]
fn trie_insertions_six_high(b: &mut Bencher) { fn trie_insertions_six_high(b: &mut Bencher) {
let mut d: Vec<(Bytes, Bytes)> = Vec::new(); let mut d: Vec<(Bytes, Bytes)> = Vec::new();

View File

@ -17,12 +17,26 @@ pub enum Alphabet {
Custom(Bytes), 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. /// Standard test map for profiling tries.
pub struct StandardMap { pub struct StandardMap {
alphabet: Alphabet, /// The alphabet to use for keys.
min_key: usize, pub alphabet: Alphabet,
journal_key: usize, /// Minimum size of key.
count: usize, 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 { impl StandardMap {
@ -71,7 +85,7 @@ impl StandardMap {
Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed), 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), 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.push((k, v))
} }
d d