This commit is contained in:
Jeffrey Wilcke 2016-09-27 14:11:22 +02:00
parent 50281f1d17
commit f80d102fe4
6 changed files with 103 additions and 31 deletions

View file

@ -18,6 +18,7 @@ package common
import ( import (
"bytes" "bytes"
"math/big"
"testing" "testing"
) )
@ -87,3 +88,37 @@ func TestBigCopy(t *testing.T) {
t.Error("Got", zbytes) t.Error("Got", zbytes)
} }
} }
var benchSize = 1000
func BenchmarkBitLen(b *testing.B) {
tests := make([]*big.Int, 0, benchSize)
for i := 0; i < benchSize; i++ {
tests = append(tests, big.NewInt(int64(i)))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < benchSize; j++ {
_ = tests[j].BitLen()
}
}
}
var bigzero = new(big.Int)
func BenchmarkCmp(b *testing.B) {
tests := make([]*big.Int, 0, benchSize)
for i := 0; i < benchSize; i++ {
tests = append(tests, big.NewInt(int64(i)))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < benchSize; j++ {
_ = tests[j].Cmp(bigzero)
}
}
}

View file

@ -85,6 +85,7 @@ func (s *State) Read(address common.Address) (object *StateObject, inCache bool)
stateObject := s.StateObjects[address] stateObject := s.StateObjects[address]
if stateObject == nil && s.parent != nil { if stateObject == nil && s.parent != nil {
stateObject, _ = s.parent.Read(address) stateObject, _ = s.parent.Read(address)
s.StateObjects[address] = stateObject
} else if stateObject != nil { } else if stateObject != nil {
inCache = true inCache = true
} }
@ -107,6 +108,7 @@ func (s *State) Read(address common.Address) (object *StateObject, inCache bool)
glog.Errorf("can't decode object at %x: %v", address[:], err) glog.Errorf("can't decode object at %x: %v", address[:], err)
return nil, false return nil, false
} }
s.StateObjects[address] = stateObject
return stateObject, false return stateObject, false
} }
@ -126,9 +128,9 @@ func (s *State) loadStateObject(stateObject *StateObject) {
} }
func (s *State) GetOrNewStateObject(address common.Address) *StateObject { func (s *State) GetOrNewStateObject(address common.Address) *StateObject {
stateObject, inCache := s.Read(address) stateObject, _ := s.Read(address)
if stateObject != nil { if stateObject != nil {
if !inCache || !s.localStateObjects[address] { if !s.localStateObjects[address] {
stateObject = stateObject.Copy() stateObject = stateObject.Copy()
s.StateObjects[address] = stateObject s.StateObjects[address] = stateObject
s.localStateObjects[address] = true s.localStateObjects[address] = true
@ -161,9 +163,10 @@ func (s *State) GetOrNewStateObject(address common.Address) *StateObject {
*/ */
func (s *State) GetStateObject(address common.Address) *StateObject { func (s *State) GetStateObject(address common.Address) *StateObject {
account, inCache := s.Read(address) account, _ := s.Read(address)
if account != nil { if account != nil {
if !inCache { if s.StateObjects[address] == nil {
//if !inCache {
s.StateObjects[address] = account s.StateObjects[address] = account
} }
return account return account
@ -189,7 +192,13 @@ func (s *State) CreateStateObject(address common.Address) *StateObject {
return stateObject return stateObject
} }
var bigzero = new(big.Int)
func (s *State) SubBalance(address common.Address, amount *big.Int) { func (s *State) SubBalance(address common.Address, amount *big.Int) {
if amount.Cmp(bigzero) == 0 {
return
}
stateObject := s.GetOrNewStateObject(address) stateObject := s.GetOrNewStateObject(address)
if stateObject != nil { if stateObject != nil {
stateObject.SubBalance(amount) stateObject.SubBalance(amount)
@ -197,6 +206,10 @@ func (s *State) SubBalance(address common.Address, amount *big.Int) {
} }
func (s *State) AddBalance(address common.Address, amount *big.Int) { func (s *State) AddBalance(address common.Address, amount *big.Int) {
if amount.Cmp(bigzero) == 0 {
return
}
stateObject := s.GetOrNewStateObject(address) stateObject := s.GetOrNewStateObject(address)
if stateObject != nil { if stateObject != nil {
stateObject.AddBalance(amount) stateObject.AddBalance(amount)

View file

@ -142,7 +142,7 @@ func opMul(instr instruction, pc *uint64, env *Environment, contract *Contract,
func opDiv(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) { func opDiv(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.pop()
if y.Cmp(common.Big0) != 0 { if y.BitLen() != 0 {
stack.push(U256(x.Div(x, y))) stack.push(U256(x.Div(x, y)))
} else { } else {
stack.push(new(big.Int)) stack.push(new(big.Int))

View file

@ -20,7 +20,6 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
) )
@ -86,8 +85,6 @@ func OptimiseProgram(program *Program) {
statsJump++ statsJump++
load = nil load = nil
case instr.op == EXTCODESIZE:
program.instructions[i] = codesize{}
default: default:
// create a new N pushes segment // create a new N pushes segment
if len(load) > 1 { if len(load) > 1 {
@ -100,22 +97,6 @@ func OptimiseProgram(program *Program) {
} }
} }
type codesize struct {
size *big.Int
}
func (instr codesize) do(program *Program, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
if instr.size == nil {
addr := common.BigToAddress(stack.pop())
instr.size = big.NewInt(int64(len(env.Db().GetCode(addr))))
}
stack.push(instr.size)
return nil, nil
}
func (codesize) Op() OpCode { return EXTCODESIZE }
func (codesize) halts() bool { return false }
// makePushSeg creates a new push segment from N amount of push instructions // makePushSeg creates a new push segment from N amount of push instructions
func makePushSeg(instrs []instruction) (pushSeg, int) { func makePushSeg(instrs []instruction) (pushSeg, int) {
var ( var (

View file

@ -26,6 +26,7 @@ import (
// initialised objects. // initialised objects.
type Stack struct { type Stack struct {
data []*big.Int data []*big.Int
count int
} }
func newstack() *Stack { func newstack() *Stack {
@ -40,16 +41,21 @@ func (st *Stack) push(d *big.Int) {
// NOTE push limit (1024) is checked in baseCheck // NOTE push limit (1024) is checked in baseCheck
//stackItem := new(big.Int).Set(d) //stackItem := new(big.Int).Set(d)
//st.data = append(st.data, stackItem) //st.data = append(st.data, stackItem)
st.data = append(st.data, d) //st.data = append(st.data, d)
st.data = append(st.data[:st.count], d)
st.count++
} }
func (st *Stack) pushN(ds ...*big.Int) { func (st *Stack) pushN(ds ...*big.Int) {
st.data = append(st.data, ds...) st.data = append(st.data[:st.count], ds...)
st.count += len(ds)
} }
func (st *Stack) pop() (ret *big.Int) { func (st *Stack) pop() *big.Int {
ret = st.data[len(st.data)-1] //ret = st.data[len(st.data)-1]
st.data = st.data[:len(st.data)-1] //st.data = st.data[:len(st.data)-1]
return
st.count--
return st.data[st.count]
} }
func (st *Stack) len() int { func (st *Stack) len() int {

View file

@ -18,6 +18,7 @@ package vm
import ( import (
"fmt" "fmt"
"sort"
"time" "time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -103,6 +104,18 @@ func (evm *EVM) Run(contract *Contract, input []byte) ([]byte, error) {
return nil, fmt.Errorf("Unexpected return using program %x", codehash) return nil, fmt.Errorf("Unexpected return using program %x", codehash)
} }
type stats struct {
op OpCode
dura time.Duration
callCount uint64
}
type statsList []stats
func (sl statsList) Len() int { return len(sl) }
func (sl statsList) Less(i, j int) bool { return sl[i].dura < sl[j].dura }
func (sl statsList) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
func (evm *EVM) runProgram(program *Program, contract *Contract, input []byte) ([]byte, error) { func (evm *EVM) runProgram(program *Program, contract *Contract, input []byte) ([]byte, error) {
contract.Input = input contract.Input = input
@ -112,7 +125,23 @@ func (evm *EVM) runProgram(program *Program, contract *Contract, input []byte) (
mem = NewMemory() mem = NewMemory()
stack = newstack() stack = newstack()
env = evm.env env = evm.env
stats = make(map[OpCode]stats)
) )
defer func() {
fmt.Println("stats for program")
i := 0
sl := make(statsList, len(stats))
for op, stat := range stats {
stat.op = op
sl[i] = stat
i++
}
sort.Sort(sort.Reverse(sl))
for _, stat := range sl {
fmt.Printf("%v: call count: %d duration: %v\n", stat.op, stat.callCount, stat.dura)
}
}()
if glog.V(logger.Debug) { if glog.V(logger.Debug) {
glog.Infof("running JIT program %x\n", program.Id[:4]) glog.Infof("running JIT program %x\n", program.Id[:4])
@ -127,11 +156,19 @@ func (evm *EVM) runProgram(program *Program, contract *Contract, input []byte) (
instrCount++ instrCount++
instr := program.instructions[pc] instr := program.instructions[pc]
tstart := time.Now()
stat := stats[instr.Op()]
stat.callCount++
if instr.Op() == DELEGATECALL && !homestead { if instr.Op() == DELEGATECALL && !homestead {
return nil, fmt.Errorf("Invalid opcode 0x%x", instr.Op()) return nil, fmt.Errorf("Invalid opcode 0x%x", instr.Op())
} }
ret, err := instr.do(program, &pc, env, contract, mem, stack) ret, err := instr.do(program, &pc, env, contract, mem, stack)
stat.dura += time.Since(tstart)
stats[instr.Op()] = stat
if err != nil { if err != nil {
//gas := new(big.Int).SetUint64(contract.gas64) //gas := new(big.Int).SetUint64(contract.gas64)
//evm.cfg.Tracer.CaptureState(evm.env, pc, instr.Op(), gas, cost, mem, stack, contract, evm.env.Depth(), err) //evm.cfg.Tracer.CaptureState(evm.env, pc, instr.Op(), gas, cost, mem, stack, contract, evm.env.Depth(), err)