Commit ab89972d authored by 袁兴强's avatar 袁兴强 Committed by vipwzw

add wasm vm cache

parent db7506a5
...@@ -74,7 +74,6 @@ func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, in ...@@ -74,7 +74,6 @@ func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, in
} }
func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index int) (*types.Receipt, error) { func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index int) (*types.Receipt, error) {
log.Info("into wasm Exec_Call...")
if payload == nil { if payload == nil {
return nil, types.ErrInvalidParam return nil, types.ErrInvalidParam
} }
...@@ -83,18 +82,26 @@ func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index ...@@ -83,18 +82,26 @@ func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index
} }
w.stateKVC = dapp.NewKVCreator(w.GetStateDB(), calcStatePrefix(payload.Contract), nil) w.stateKVC = dapp.NewKVCreator(w.GetStateDB(), calcStatePrefix(payload.Contract), nil)
code, err := w.stateKVC.GetNoPrefix(contractKey(payload.Contract)) var vm *exec.VirtualMachine
if err != nil { var ok bool
return nil, err if vm, ok = w.VMCache[payload.Contract]; !ok {
} code, err := w.stateKVC.GetNoPrefix(contractKey(payload.Contract))
vm, err := exec.NewVirtualMachine(code, exec.VMConfig{ if err != nil {
DefaultMemoryPages: 128, return nil, err
DefaultTableSize: 128, }
DisableFloatingPoint: true, vm, err = exec.NewVirtualMachine(code, exec.VMConfig{
GasLimit: uint64(tx.Fee), DefaultMemoryPages: 128,
}, new(Resolver), &compiler.SimpleGasPolicy{GasPerInstruction: 1}) DefaultTableSize: 128,
if err != nil { DisableFloatingPoint: true,
return nil, err GasLimit: uint64(tx.Fee),
}, new(Resolver), &compiler.SimpleGasPolicy{GasPerInstruction: 1})
if err != nil {
return nil, err
}
w.VMCache[payload.Contract] = vm
} else {
vm.Config.GasLimit = uint64(tx.Fee)
vm.Gas = 0
} }
// Get the function ID of the entry function to be executed. // Get the function ID of the entry function to be executed.
...@@ -115,7 +122,6 @@ func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index ...@@ -115,7 +122,6 @@ func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index
if err != nil { if err != nil {
return nil, err return nil, err
} }
var kvs []*types.KeyValue var kvs []*types.KeyValue
kvs = append(kvs, w.kvs...) kvs = append(kvs, w.kvs...)
kvs = append(kvs, w.stateKVC.KVList()...) kvs = append(kvs, w.stateKVC.KVList()...)
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
drivers "github.com/33cn/chain33/system/dapp" drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
types2 "github.com/33cn/plugin/plugin/dapp/wasm/types" types2 "github.com/33cn/plugin/plugin/dapp/wasm/types"
"github.com/perlin-network/life/exec"
) )
var driverName = types2.WasmX var driverName = types2.WasmX
...@@ -36,10 +37,13 @@ type Wasm struct { ...@@ -36,10 +37,13 @@ type Wasm struct {
customLogs []string customLogs []string
execAddr string execAddr string
contractName string contractName string
VMCache map[string]*exec.VirtualMachine
} }
func newWasm() drivers.Driver { func newWasm() drivers.Driver {
d := &Wasm{} d := &Wasm{
VMCache: make(map[string]*exec.VirtualMachine),
}
d.SetChild(d) d.SetChild(d)
d.SetExecutorType(types.LoadExecutorType(driverName)) d.SetExecutorType(types.LoadExecutorType(driverName))
return d return d
......
package executor package executor
import ( import (
"encoding/hex"
"io/ioutil" "io/ioutil"
"strings" "strings"
"testing" "testing"
...@@ -41,10 +42,54 @@ func init() { ...@@ -41,10 +42,54 @@ func init() {
Init(types2.WasmX, cfg, nil) Init(types2.WasmX, cfg, nil)
} }
func BenchmarkWasm_Exec_Call(b *testing.B) {
dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb)
acc := initAccount(ldb)
testCreate(b, acc, kvdb)
testCall(b, acc, kvdb)
payload := types2.WasmAction{
Ty: types2.WasmActionCall,
Value: &types2.WasmAction_Call{
Call: &types2.WasmCall{
Contract: "dice",
Method: "play",
Parameters: []int64{1, 10},
},
},
}
tx := &types.Transaction{
Payload: types.Encode(&payload),
}
tx, err := types.FormatTx(cfg, types2.WasmX, tx)
require.Nil(b, err, "format tx error")
err = signTx(tx, PrivKeys[1])
require.Nil(b, err)
wasm := newWasm()
wasm.SetCoinsAccount(acc)
wasm.SetStateDB(kvdb)
api := mocks.QueueProtocolAPI{}
api.On("GetConfig").Return(cfg)
api.On("GetRandNum", mock.Anything).Return(hex.DecodeString("0x0b1f047927e1c42327bdd3222558eaf7b10b998e7a9bb8144e4b2a27ffa53df3"))
wasm.SetAPI(&api)
wasmCB = wasm.(*Wasm)
err = transferToExec(Addrs[1], wasmAddr, 1e9)
require.Nil(b, err)
wasmCB = nil
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := wasm.Exec(tx, 0)
require.Nil(b, err)
}
b.StopTimer()
}
func TestWasm_Exec(t *testing.T) { func TestWasm_Exec(t *testing.T) {
dir, ldb, kvdb := util.CreateTestDB() dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb) defer util.CloseTestDB(dir, ldb)
acc := initAccount(t, ldb) acc := initAccount(ldb)
testCreate(t, acc, kvdb) testCreate(t, acc, kvdb)
testCall(t, acc, kvdb) testCall(t, acc, kvdb)
...@@ -54,7 +99,7 @@ func TestWasm_Callback(t *testing.T) { ...@@ -54,7 +99,7 @@ func TestWasm_Callback(t *testing.T) {
dir, ldb, kvdb := util.CreateTestDB() dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb) defer util.CloseTestDB(dir, ldb)
wasmCB = newWasm().(*Wasm) wasmCB = newWasm().(*Wasm)
acc := initAccount(t, ldb) acc := initAccount(ldb)
wasmCB.SetCoinsAccount(acc) wasmCB.SetCoinsAccount(acc)
wasmCB.SetStateDB(kvdb) wasmCB.SetStateDB(kvdb)
wasmCB.SetLocalDB(kvdb) wasmCB.SetLocalDB(kvdb)
...@@ -218,7 +263,7 @@ func TestWasm_Callback(t *testing.T) { ...@@ -218,7 +263,7 @@ func TestWasm_Callback(t *testing.T) {
t.Log(random) t.Log(random)
} }
func testCreate(t *testing.T, acc *account.DB, stateDB db.KV) { func testCreate(t testing.TB, acc *account.DB, stateDB db.KV) {
code, err := ioutil.ReadFile("../contracts/dice/dice.wasm") code, err := ioutil.ReadFile("../contracts/dice/dice.wasm")
require.Nil(t, err, "read wasm file error") require.Nil(t, err, "read wasm file error")
payload := types2.WasmAction{ payload := types2.WasmAction{
...@@ -253,7 +298,7 @@ func testCreate(t *testing.T, acc *account.DB, stateDB db.KV) { ...@@ -253,7 +298,7 @@ func testCreate(t *testing.T, acc *account.DB, stateDB db.KV) {
require.Nil(t, err) require.Nil(t, err)
} }
func testCall(t *testing.T, acc *account.DB, stateDB db.KV) { func testCall(t testing.TB, acc *account.DB, stateDB db.KV) {
payload := types2.WasmAction{ payload := types2.WasmAction{
Ty: types2.WasmActionCall, Ty: types2.WasmActionCall,
Value: &types2.WasmAction_Call{ Value: &types2.WasmAction_Call{
...@@ -287,16 +332,18 @@ func testCall(t *testing.T, acc *account.DB, stateDB db.KV) { ...@@ -287,16 +332,18 @@ func testCall(t *testing.T, acc *account.DB, stateDB db.KV) {
require.Equal(t, int32(types2.TyLogWasmCall), receipt.Logs[0].Ty) require.Equal(t, int32(types2.TyLogWasmCall), receipt.Logs[0].Ty)
} }
func initAccount(t *testing.T, db db.KV) *account.DB { func initAccount(db db.KV) *account.DB {
wasmAddr = address.ExecAddress(cfg.ExecName(types2.WasmX)) wasmAddr = address.ExecAddress(cfg.ExecName(types2.WasmX))
acc, err := account.NewAccountDB(cfg, "coins", "bty", db) acc, err := account.NewAccountDB(cfg, "coins", "bty", db)
require.Nil(t, err, "new account db error") if err != nil {
panic(err)
}
acc.SaveAccount(&types.Account{ acc.SaveAccount(&types.Account{
Balance: 1e10, Balance: 1e15,
Addr: Addrs[0], Addr: Addrs[0],
}) })
acc.SaveAccount(&types.Account{ acc.SaveAccount(&types.Account{
Balance: 1e10, Balance: 1e15,
Addr: Addrs[1], Addr: Addrs[1],
}) })
return acc return acc
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment