Skip to content

Commit

Permalink
perf: use a sync pool for machine constructor (#625)
Browse files Browse the repository at this point in the history
perf: use a sync pool for machine constructor
  • Loading branch information
peter7891 authored Mar 30, 2023
1 parent 28c1984 commit 41af8f6
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 7 deletions.
2 changes: 2 additions & 0 deletions cmd/gnodev/repl.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ func runRepl(rootDir string, verbose bool) error {
Store: testStore,
})

defer m.Release()

// init termui
rw := struct {
io.Reader
Expand Down
2 changes: 2 additions & 0 deletions cmd/gnodev/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ func execRun(cfg *runCfg, args []string, io *commands.IO) error {
Store: testStore,
})

defer m.Release()

// read files
files := make([]*gno.FileNode, len(args))
for i, fname := range args {
Expand Down
51 changes: 48 additions & 3 deletions pkgs/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"reflect"
"strings"
"sync"
"testing"

"github.com/gnolang/gno/pkgs/errors"
Expand Down Expand Up @@ -44,6 +45,8 @@ type Machine struct {
Context interface{}
}

// machine.Release() must be called on objects
// created via this constructor
// Machine with new package of given path.
// Creates a new MemRealmer for any new realms.
// Looks in store for package of pkgPath; if not found,
Expand All @@ -70,6 +73,19 @@ type MachineOptions struct {
MaxCycles int64 // or 0 for no limit.
}

// the machine constructor gets spammed
// this causes a significant part of the runtime and memory
// to be occupied by *Machine
// hence, this pool
var machinePool = sync.Pool{
New: func() interface{} {
return &Machine{
Ops: make([]Op, OpSize),
Values: make([]TypedValue, ValueSize),
}
},
}

func NewMachineWithOptions(opts MachineOptions) *Machine {
checkTypes := opts.CheckTypes
readOnly := opts.ReadOnly
Expand Down Expand Up @@ -99,10 +115,11 @@ func NewMachineWithOptions(opts MachineOptions) *Machine {
}
}
context := opts.Context
mm := &Machine{
Ops: make([]Op, 1024),
mm := machinePool.Get().(*Machine)
*mm = Machine{
Ops: mm.Ops,
NumOps: 0,
Values: make([]TypedValue, 1024),
Values: mm.Values,
NumValues: 0,
Package: pv,
Alloc: alloc,
Expand All @@ -113,12 +130,40 @@ func NewMachineWithOptions(opts MachineOptions) *Machine {
Store: store,
Context: context,
}

if pv != nil {
mm.SetActivePackage(pv)
}
return mm
}

const (
OpSize = 1024
ValueSize = 1024
)

var (
opZeroed [OpSize]Op
valueZeroed [ValueSize]TypedValue
)

// m should not be used after this call
// if m is nil, this will panic
// this is on purpose, to discourage misuse
// and prevent objects that were not taken from
// the pool, to call Release
func (m *Machine) Release() {
// copy()
// here we zero in the values for the next user
m.NumOps = 0
m.NumValues = 0
// this is the fastest way to zero-in a slice in Go
copy(m.Ops, opZeroed[:0])
copy(m.Values, valueZeroed[:0])

machinePool.Put(m)
}

func (m *Machine) SetActivePackage(pv *PackageValue) {
if err := m.CheckEmpty(); err != nil {
panic(errors.Wrap(err, "set package when machine not empty"))
Expand Down
14 changes: 10 additions & 4 deletions pkgs/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,9 @@ func evalStaticType(store Store, last BlockNode, x Expr) Type {
store = store.Fork()
store.SetCachePackage(pv)
}
tv := NewMachine(pn.PkgPath, store).EvalStatic(last, x)
m := NewMachine(pn.PkgPath, store)
tv := m.EvalStatic(last, x)
m.Release()
if _, ok := tv.V.(TypeValue); !ok {
panic(fmt.Sprintf("%s is not a type", x.String()))
}
Expand Down Expand Up @@ -2053,7 +2055,9 @@ func evalStaticTypeOfRaw(store Store, last BlockNode, x Expr) (t Type) {
store = store.Fork()
store.SetCachePackage(pv)
}
t = NewMachine(pn.PkgPath, store).EvalStaticTypeOf(last, x)
m := NewMachine(pn.PkgPath, store)
t = m.EvalStaticTypeOf(last, x)
m.Release()
x.SetAttribute(ATTR_TYPEOF_VALUE, t)
return t
}
Expand Down Expand Up @@ -2147,10 +2151,12 @@ func getResultTypedValues(cx *CallExpr) []TypedValue {
func evalConst(store Store, last BlockNode, x Expr) *ConstExpr {
// TODO: some check or verification for ensuring x
// is constant? From the machine?
cv := NewMachine(".dontcare", store).EvalStatic(last, x)
cv := NewMachine(".dontcare", store)
tv := cv.EvalStatic(last, x)
cv.Release()
cx := &ConstExpr{
Source: x,
TypedValue: cv,
TypedValue: tv,
}
cx.SetAttribute(ATTR_PREPROCESSED, true)
setConstAttrs(cx)
Expand Down
1 change: 1 addition & 0 deletions pkgs/gnolang/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2476,6 +2476,7 @@ func applySpecifics(lookup map[Name]Type, tmpl Type) (Type, bool) {
// Evaluate type from generic expression.
m := NewMachine("", nil)
tv := m.EvalStatic(bs, gx)
m.Release()
if isElem {
return tv.GetType().Elem(), true
} else {
Expand Down
1 change: 1 addition & 0 deletions pkgs/sdk/vm/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func (vm *VMKeeper) initBuiltinPackagesAndTypes(store gno.Store) {
Output: os.Stdout,
Store: store,
})
defer m2.Release()
return m2.RunMemPackage(memPkg, true)
}
store.SetPackageGetter(getPackage)
Expand Down
5 changes: 5 additions & 0 deletions pkgs/sdk/vm/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func (vm *VMKeeper) Initialize(ms store.MultiStore) {
Output: os.Stdout, // XXX
Store: vm.gnoStore,
})
defer m2.Release()
gno.DisableDebug()
m2.PreprocessAllFilesAndSaveBlockNodes()
gno.EnableDebug()
Expand Down Expand Up @@ -173,6 +174,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) error {
Context: msgCtx,
MaxCycles: 10 * 1000 * 1000, // 10M cycles // XXX
})
defer m2.Release()
m2.RunMemPackage(memPkg, true)
fmt.Println("CPUCYCLES addpkg", m2.Cycles)
return nil
Expand Down Expand Up @@ -253,6 +255,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) {
r, m.String())
return
}
m.Release()
}()
rtvs := m.Eval(xn)
fmt.Println("CPUCYCLES call", m.Cycles)
Expand Down Expand Up @@ -372,6 +375,7 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res
r, m.String())
return
}
m.Release()
}()
rtvs := m.Eval(xx)
res = ""
Expand Down Expand Up @@ -431,6 +435,7 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string
r, m.String())
return
}
m.Release()
}()
rtvs := m.Eval(xx)
if len(rtvs) != 1 {
Expand Down

0 comments on commit 41af8f6

Please sign in to comment.