experimental: optimize function listener context stack (#1445)
This commit is contained in:
@@ -135,7 +135,7 @@ type (
|
||||
ctx context.Context
|
||||
// contextStack is a stack of contexts which is pushed and popped by function listeners.
|
||||
// This is used and modified when there are function listeners.
|
||||
contextStack *contextStack
|
||||
contextStack []context.Context
|
||||
|
||||
// stackIterator provides a way to iterate over the stack for Listeners.
|
||||
// It is setup and valid only during a call to a Listener hook.
|
||||
@@ -144,14 +144,6 @@ type (
|
||||
ensureTermination bool
|
||||
}
|
||||
|
||||
// contextStack is a stack of context.Context.
|
||||
contextStack struct {
|
||||
// See note at top of file before modifying this struct.
|
||||
|
||||
self context.Context
|
||||
prev *contextStack
|
||||
}
|
||||
|
||||
// moduleContext holds the per-function call specific module information.
|
||||
// This is subject to be manipulated from compiled native code whenever we make function calls.
|
||||
moduleContext struct {
|
||||
@@ -1175,9 +1167,8 @@ func (ce *callEngine) builtinFunctionFunctionListenerBefore(ctx context.Context,
|
||||
|
||||
params := ce.stack[base : base+fn.funcType.ParamNumInUint64]
|
||||
listerCtx := fn.parent.listener.Before(ctx, mod, fn.definition(), params, &ce.stackIterator)
|
||||
prevStackTop := ce.contextStack
|
||||
ce.contextStack = &contextStack{self: ctx, prev: prevStackTop}
|
||||
|
||||
ce.contextStack = append(ce.contextStack, ctx)
|
||||
ce.ctx = listerCtx
|
||||
ce.stackIterator.clear()
|
||||
}
|
||||
@@ -1185,8 +1176,11 @@ func (ce *callEngine) builtinFunctionFunctionListenerBefore(ctx context.Context,
|
||||
func (ce *callEngine) builtinFunctionFunctionListenerAfter(ctx context.Context, mod api.Module, fn *function) {
|
||||
base := int(ce.stackBasePointerInBytes >> 3)
|
||||
fn.parent.listener.After(ctx, mod, fn.definition(), nil, ce.stack[base:base+fn.funcType.ResultNumInUint64])
|
||||
ce.ctx = ce.contextStack.self
|
||||
ce.contextStack = ce.contextStack.prev
|
||||
|
||||
i := len(ce.contextStack) - 1
|
||||
ce.ctx = ce.contextStack[i]
|
||||
ce.contextStack[i] = nil
|
||||
ce.contextStack = ce.contextStack[:i]
|
||||
}
|
||||
|
||||
func compileGoDefinedHostFunction(cmp compiler) (body []byte, err error) {
|
||||
|
||||
44
internal/engine/compiler/engine_bench_test.go
Normal file
44
internal/engine/compiler/engine_bench_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
func BenchmarkCallEngine_builtinFunctionFunctionListener(b *testing.B) {
|
||||
f := &function{
|
||||
funcType: &wasm.FunctionType{ParamNumInUint64: 3},
|
||||
parent: &compiledFunction{
|
||||
listener: mockListener{
|
||||
before: func(context.Context, api.Module, api.FunctionDefinition, []uint64, experimental.StackIterator) context.Context {
|
||||
return context.Background()
|
||||
},
|
||||
after: func(context.Context, api.Module, api.FunctionDefinition, error, []uint64) {
|
||||
},
|
||||
},
|
||||
index: 0,
|
||||
parent: &compiledModule{
|
||||
source: &wasm.Module{
|
||||
FunctionDefinitionSection: []wasm.FunctionDefinition{{}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ce := &callEngine{
|
||||
ctx: context.Background(),
|
||||
stack: []uint64{0, 1, 2, 3, 4, 0, 0, 0},
|
||||
stackContext: stackContext{stackBasePointerInBytes: 16},
|
||||
}
|
||||
|
||||
module := new(wasm.ModuleInstance)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
ce.builtinFunctionFunctionListenerBefore(ce.ctx, module, f)
|
||||
ce.builtinFunctionFunctionListenerAfter(ce.ctx, module, f)
|
||||
}
|
||||
}
|
||||
@@ -605,13 +605,13 @@ func TestCallEngine_builtinFunctionFunctionListenerBefore(t *testing.T) {
|
||||
ce := &callEngine{
|
||||
ctx: currentContext, stack: []uint64{0, 1, 2, 3, 4, 0, 0, 0},
|
||||
stackContext: stackContext{stackBasePointerInBytes: 16},
|
||||
contextStack: &contextStack{self: prevContext},
|
||||
contextStack: []context.Context{prevContext},
|
||||
}
|
||||
ce.builtinFunctionFunctionListenerBefore(ce.ctx, &wasm.ModuleInstance{}, f)
|
||||
|
||||
// Contexts must be stacked.
|
||||
require.Equal(t, currentContext, ce.contextStack.self)
|
||||
require.Equal(t, prevContext, ce.contextStack.prev.self)
|
||||
require.Equal(t, currentContext, ce.contextStack[1])
|
||||
require.Equal(t, prevContext, ce.contextStack[0])
|
||||
}
|
||||
|
||||
func TestCallEngine_builtinFunctionFunctionListenerAfter(t *testing.T) {
|
||||
@@ -635,12 +635,12 @@ func TestCallEngine_builtinFunctionFunctionListenerAfter(t *testing.T) {
|
||||
ce := &callEngine{
|
||||
ctx: currentContext, stack: []uint64{0, 1, 2, 3, 4, 5},
|
||||
stackContext: stackContext{stackBasePointerInBytes: 40},
|
||||
contextStack: &contextStack{self: prevContext},
|
||||
contextStack: []context.Context{prevContext},
|
||||
}
|
||||
ce.builtinFunctionFunctionListenerAfter(ce.ctx, &wasm.ModuleInstance{}, f)
|
||||
|
||||
// Contexts must be popped.
|
||||
require.Nil(t, ce.contextStack)
|
||||
require.Equal(t, 0, len(ce.contextStack))
|
||||
require.Equal(t, prevContext, ce.ctx)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user