experimental: optimize function listener context stack (#1445)

This commit is contained in:
Achille
2023-05-09 08:10:12 -07:00
committed by GitHub
parent 6503e82d3c
commit 509827a23f
3 changed files with 56 additions and 18 deletions

View File

@@ -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) {

View 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)
}
}

View File

@@ -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)
}