Adjustable stack size for EVM (#2483)
* stack size for io workers & evm threshold * rust way to remember stack size * right value * 24kb size * some stack reduction
This commit is contained in:
parent
75d9174294
commit
ac0ae2442f
@ -25,10 +25,10 @@ use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, E
|
|||||||
use crossbeam;
|
use crossbeam;
|
||||||
pub use types::executed::{Executed, ExecutionResult};
|
pub use types::executed::{Executed, ExecutionResult};
|
||||||
|
|
||||||
/// Max depth to avoid stack overflow (when it's reached we start a new thread with VM)
|
/// Roughly estimate what stack size each level of evm depth will use
|
||||||
/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132)
|
/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132)
|
||||||
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
|
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
|
||||||
const MAX_VM_DEPTH_FOR_THREAD: usize = 64;
|
const STACK_SIZE_PER_DEPTH: usize = 24*1024;
|
||||||
|
|
||||||
/// Returns new address created from address and given nonce.
|
/// Returns new address created from address and given nonce.
|
||||||
pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
||||||
@ -149,12 +149,13 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
// TODO: we might need bigints here, or at least check overflows.
|
// TODO: we might need bigints here, or at least check overflows.
|
||||||
let balance = self.state.balance(&sender);
|
let balance = self.state.balance(&sender);
|
||||||
let gas_cost = U512::from(t.gas) * U512::from(t.gas_price);
|
let gas_cost = t.gas.full_mul(t.gas_price);
|
||||||
let total_cost = U512::from(t.value) + gas_cost;
|
let total_cost = U512::from(t.value) + gas_cost;
|
||||||
|
|
||||||
// avoid unaffordable transactions
|
// avoid unaffordable transactions
|
||||||
if U512::from(balance) < total_cost {
|
let balance512 = U512::from(balance);
|
||||||
return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: U512::from(balance) }));
|
if balance512 < total_cost {
|
||||||
|
return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: balance512 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: there can be no invalid transactions from this point.
|
// NOTE: there can be no invalid transactions from this point.
|
||||||
@ -212,8 +213,11 @@ impl<'a> Executive<'a> {
|
|||||||
tracer: &mut T,
|
tracer: &mut T,
|
||||||
vm_tracer: &mut V
|
vm_tracer: &mut V
|
||||||
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
||||||
|
|
||||||
|
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
|
||||||
|
|
||||||
// Ordinary execution - keep VM in same thread
|
// Ordinary execution - keep VM in same thread
|
||||||
if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 {
|
if (self.depth + 1) % depth_threshold != 0 {
|
||||||
let vm_factory = self.vm_factory;
|
let vm_factory = self.vm_factory;
|
||||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer);
|
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer);
|
||||||
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
||||||
@ -413,7 +417,7 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
// real ammount to refund
|
// real ammount to refund
|
||||||
let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() };
|
let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() };
|
||||||
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2));
|
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1);
|
||||||
let gas_left = gas_left_prerefund + refunded;
|
let gas_left = gas_left_prerefund + refunded;
|
||||||
|
|
||||||
let gas_used = t.gas - gas_left;
|
let gas_used = t.gas - gas_left;
|
||||||
|
@ -68,6 +68,8 @@ mod panics;
|
|||||||
use mio::{EventLoop, Token};
|
use mio::{EventLoop, Token};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
pub use worker::LOCAL_STACK_SIZE;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// IO Error
|
/// IO Error
|
||||||
pub enum IoError {
|
pub enum IoError {
|
||||||
|
@ -22,9 +22,19 @@ use crossbeam::sync::chase_lev;
|
|||||||
use service::{HandlerId, IoChannel, IoContext};
|
use service::{HandlerId, IoChannel, IoContext};
|
||||||
use IoHandler;
|
use IoHandler;
|
||||||
use panics::*;
|
use panics::*;
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
|
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
|
||||||
|
|
||||||
|
const STACK_SIZE: usize = 16*1024*1024;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
/// Stack size
|
||||||
|
/// Should be modified if it is changed in Rust since it is no way
|
||||||
|
/// to know or get it
|
||||||
|
pub static LOCAL_STACK_SIZE: Cell<usize> = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
pub enum WorkType<Message> {
|
pub enum WorkType<Message> {
|
||||||
Readable,
|
Readable,
|
||||||
Writable,
|
Writable,
|
||||||
@ -66,8 +76,9 @@ impl Worker {
|
|||||||
deleting: deleting.clone(),
|
deleting: deleting.clone(),
|
||||||
wait_mutex: wait_mutex.clone(),
|
wait_mutex: wait_mutex.clone(),
|
||||||
};
|
};
|
||||||
worker.thread = Some(thread::Builder::new().name(format!("IO Worker #{}", index)).spawn(
|
worker.thread = Some(thread::Builder::new().stack_size(STACK_SIZE).name(format!("IO Worker #{}", index)).spawn(
|
||||||
move || {
|
move || {
|
||||||
|
LOCAL_STACK_SIZE.with(|val| val.set(STACK_SIZE));
|
||||||
panic_handler.catch_panic(move || {
|
panic_handler.catch_panic(move || {
|
||||||
Worker::work_loop(stealer, channel.clone(), wait, wait_mutex.clone(), deleting)
|
Worker::work_loop(stealer, channel.clone(), wait, wait_mutex.clone(), deleting)
|
||||||
}).unwrap()
|
}).unwrap()
|
||||||
|
Loading…
Reference in New Issue
Block a user