mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
core/vm: speed up stack
This commit is contained in:
parent
06990c1544
commit
04023e6120
3 changed files with 43 additions and 26 deletions
|
|
@ -991,13 +991,13 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
||||||
start = min(codeLen, int(*pc+1))
|
start = min(codeLen, int(*pc+1))
|
||||||
end = min(codeLen, start+pushByteSize)
|
end = min(codeLen, start+pushByteSize)
|
||||||
)
|
)
|
||||||
a := new(uint256.Int).SetBytes(scope.Contract.Code[start:end])
|
a := scope.Stack.get()
|
||||||
|
a.SetBytes(scope.Contract.Code[start:end])
|
||||||
|
|
||||||
// Missing bytes: pushByteSize - len(pushData)
|
// Missing bytes: pushByteSize - len(pushData)
|
||||||
if missing := pushByteSize - (end - start); missing > 0 {
|
if missing := pushByteSize - (end - start); missing > 0 {
|
||||||
a.Lsh(a, uint(8*missing))
|
a.Lsh(a, uint(8*missing))
|
||||||
}
|
}
|
||||||
scope.Stack.push(a)
|
|
||||||
*pc += size
|
*pc += size
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
|
@ -283,23 +284,38 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
||||||
stack = newStackForTesting()
|
stack = newStackForTesting()
|
||||||
scope = &ScopeContext{nil, stack, nil}
|
code = []byte{}
|
||||||
|
opPush32 = makePush(32, 32)
|
||||||
)
|
)
|
||||||
// convert args
|
// convert args
|
||||||
intArgs := make([]*uint256.Int, len(args))
|
intArgs := make([]*uint256.Int, len(args))
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
|
code = append(code, common.LeftPadBytes(common.Hex2Bytes(arg), 32)...)
|
||||||
intArgs[i] = new(uint256.Int).SetBytes(common.Hex2Bytes(arg))
|
intArgs[i] = new(uint256.Int).SetBytes(common.Hex2Bytes(arg))
|
||||||
}
|
}
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
|
scope := &ScopeContext{nil, stack, &Contract{Code: code}}
|
||||||
|
start := time.Now()
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
for _, arg := range intArgs {
|
for range len(args) {
|
||||||
stack.push(arg)
|
opPush32(&pc, evm.interpreter, scope)
|
||||||
|
pc += 32
|
||||||
}
|
}
|
||||||
op(&pc, evm.interpreter, scope)
|
op(&pc, evm.interpreter, scope)
|
||||||
stack.pop()
|
opPop(&pc, evm.interpreter, scope)
|
||||||
}
|
}
|
||||||
bench.StopTimer()
|
bench.StopTimer()
|
||||||
|
elapsed := uint64(time.Since(start))
|
||||||
|
if elapsed < 1 {
|
||||||
|
elapsed = 1
|
||||||
|
}
|
||||||
|
reqGas := uint64(len(args))*GasFastestStep + GasFastestStep + GasQuickStep
|
||||||
|
gasUsed := reqGas * uint64(bench.N)
|
||||||
|
bench.ReportMetric(float64(reqGas), "gas/op")
|
||||||
|
// Keep it as uint64, multiply 100 to get two digit float later
|
||||||
|
mgasps := (100 * 1000 * gasUsed) / elapsed
|
||||||
|
bench.ReportMetric(float64(mgasps)/100, "mgas/s")
|
||||||
|
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
want := new(uint256.Int).SetBytes(common.Hex2Bytes(arg))
|
want := new(uint256.Int).SetBytes(common.Hex2Bytes(arg))
|
||||||
|
|
|
||||||
|
|
@ -29,28 +29,24 @@ type stackArena struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *stackArena) push(value *uint256.Int) {
|
func (sa *stackArena) push(value *uint256.Int) {
|
||||||
if len(sa.data) <= sa.top {
|
|
||||||
// we need to grow the arena
|
|
||||||
sa.data = slices.Grow(sa.data, 512)
|
|
||||||
sa.data = sa.data[:cap(sa.data)]
|
|
||||||
}
|
|
||||||
sa.data[sa.top] = *value
|
|
||||||
sa.top++
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sa *stackArena) pop() {
|
|
||||||
sa.top--
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArena() *stackArena {
|
func newArena() *stackArena {
|
||||||
return &stackArena{
|
return &stackArena{
|
||||||
data: make([]uint256.Int, 1024),
|
data: make([]uint256.Int, 1025),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stack returns an instance of a stack which uses the underlying arena. The instance
|
// stack returns an instance of a stack which uses the underlying arena. The instance
|
||||||
// must be released by invoking the (*Stack).release() method
|
// must be released by invoking the (*Stack).release() method
|
||||||
func (sa *stackArena) stack() *Stack {
|
func (sa *stackArena) stack() *Stack {
|
||||||
|
// make sure every substack has at least 1024 elements
|
||||||
|
if len(sa.data) <= sa.top+1024 {
|
||||||
|
// we need to grow the arena
|
||||||
|
sa.data = slices.Grow(sa.data, 1024)
|
||||||
|
sa.data = sa.data[:cap(sa.data)]
|
||||||
|
}
|
||||||
return &Stack{
|
return &Stack{
|
||||||
bottom: sa.top,
|
bottom: sa.top,
|
||||||
size: 0,
|
size: 0,
|
||||||
|
|
@ -62,7 +58,7 @@ func (sa *stackArena) stack() *Stack {
|
||||||
// backed by a newly allocated arena.
|
// backed by a newly allocated arena.
|
||||||
func newStackForTesting() *Stack {
|
func newStackForTesting() *Stack {
|
||||||
arena := &stackArena{
|
arena := &stackArena{
|
||||||
data: make([]uint256.Int, 256),
|
data: make([]uint256.Int, 1025),
|
||||||
}
|
}
|
||||||
return arena.stack()
|
return arena.stack()
|
||||||
}
|
}
|
||||||
|
|
@ -89,16 +85,22 @@ func (s *Stack) Data() []uint256.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) push(d *uint256.Int) {
|
func (s *Stack) push(d *uint256.Int) {
|
||||||
// NOTE push limit (1024) is checked in baseCheck
|
s.inner.data[s.inner.top] = *d
|
||||||
s.inner.push(d)
|
s.inner.top++
|
||||||
s.size++
|
s.size++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Stack) get() *uint256.Int {
|
||||||
|
elem := &s.inner.data[s.inner.top]
|
||||||
|
s.inner.top++
|
||||||
|
s.size++
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Stack) pop() uint256.Int {
|
func (s *Stack) pop() uint256.Int {
|
||||||
ret := s.inner.data[s.bottom+s.size-1]
|
s.inner.top--
|
||||||
s.inner.pop()
|
|
||||||
s.size--
|
s.size--
|
||||||
return ret
|
return s.inner.data[s.inner.top]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) len() int {
|
func (s *Stack) len() int {
|
||||||
|
|
@ -155,7 +157,6 @@ func (s *Stack) swap16() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) dup(n int) {
|
func (s *Stack) dup(n int) {
|
||||||
// TODO: check size of inner
|
|
||||||
s.inner.data[s.bottom+s.size] = s.inner.data[s.bottom+s.size-n]
|
s.inner.data[s.bottom+s.size] = s.inner.data[s.bottom+s.size-n]
|
||||||
s.size++
|
s.size++
|
||||||
s.inner.top++
|
s.inner.top++
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue