Adds tests for multiple goroutines (#331)

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
Takeshi Yoneda
2022-03-04 18:19:26 +09:00
committed by GitHub
parent 4d1fe9e3b8
commit 82aec51eb9
4 changed files with 83 additions and 38 deletions

View File

@@ -2,6 +2,8 @@
package wazero package wazero
const JITSupported = true
// NewRuntimeConfig returns NewRuntimeConfigJIT // NewRuntimeConfig returns NewRuntimeConfigJIT
func NewRuntimeConfig() *RuntimeConfig { func NewRuntimeConfig() *RuntimeConfig {
return NewRuntimeConfigJIT() return NewRuntimeConfigJIT()

View File

@@ -2,6 +2,8 @@
package wazero package wazero
const JITSupported = false
// NewRuntimeConfig returns NewRuntimeConfigInterpreter // NewRuntimeConfig returns NewRuntimeConfigInterpreter
func NewRuntimeConfig() *RuntimeConfig { func NewRuntimeConfig() *RuntimeConfig {
return NewRuntimeConfigInterpreter() return NewRuntimeConfigInterpreter()

View File

@@ -5,8 +5,6 @@ import (
_ "embed" _ "embed"
"fmt" "fmt"
"math" "math"
"runtime"
"sync"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -19,15 +17,15 @@ import (
// ctx is a default context used to avoid lint warnings even though these tests don't use any context data. // ctx is a default context used to avoid lint warnings even though these tests don't use any context data.
var ctx = context.Background() var ctx = context.Background()
func TestJIT(t *testing.T) { func TestJITAdhoc(t *testing.T) {
if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" { if !wazero.JITSupported {
t.Skip() t.Skip()
} }
runTests(t, wazero.NewRuntimeConfigJIT) runAdhocTests(t, wazero.NewRuntimeConfigJIT)
} }
func TestInterpreter(t *testing.T) { func TestInterpreterAdhoc(t *testing.T) {
runTests(t, wazero.NewRuntimeConfigInterpreter) runAdhocTests(t, wazero.NewRuntimeConfigInterpreter)
} }
var ( var (
@@ -45,7 +43,7 @@ var (
hugestackWasm []byte hugestackWasm []byte
) )
func runTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) { func runAdhocTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
t.Run("huge stack", func(t *testing.T) { t.Run("huge stack", func(t *testing.T) {
testHugeStack(t, newRuntimeConfig) testHugeStack(t, newRuntimeConfig)
}) })
@@ -73,35 +71,18 @@ func runTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
} }
func testHugeStack(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) { func testHugeStack(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
// We execute 1000 times in order to ensure the JIT engine is stable under high concurrency
// and we have no conflict with Go's runtime.
const goroutines = 1000
r := wazero.NewRuntimeWithConfig(newRuntimeConfig()) r := wazero.NewRuntimeWithConfig(newRuntimeConfig())
module, err := r.NewModuleFromSource(hugestackWasm) module, err := r.NewModuleFromSource(hugestackWasm)
require.NoError(t, err) require.NoError(t, err)
fn := module.Function("main") fn := module.Function("main")
require.NotNil(t, fn) require.NotNil(t, fn)
var wg sync.WaitGroup _, err = fn.Call(ctx)
wg.Add(goroutines) require.NoError(t, err)
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
_, err = fn.Call(ctx)
require.NoError(t, err)
}()
}
wg.Wait()
} }
func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) { func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
// We execute 1000 times in order to ensure the JIT engine is stable under high concurrency
// and we have no conflict with Go's runtime.
const goroutines = 1000
r := wazero.NewRuntimeWithConfig(newRuntimeConfig()) r := wazero.NewRuntimeWithConfig(newRuntimeConfig())
module, err := r.NewModuleFromSource(fibWasm) module, err := r.NewModuleFromSource(fibWasm)
require.NoError(t, err) require.NoError(t, err)
@@ -109,17 +90,9 @@ func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig)
fib := module.Function("fib") fib := module.Function("fib")
require.NotNil(t, fib) require.NotNil(t, fib)
var wg sync.WaitGroup results, err := fib.Call(ctx, 20)
wg.Add(goroutines) require.NoError(t, err)
for i := 0; i < goroutines; i++ { require.Equal(t, uint64(10946), results[0])
go func() {
defer wg.Done()
results, err := fib.Call(ctx, 20)
require.NoError(t, err)
require.Equal(t, uint64(10946), results[0])
}()
}
wg.Wait()
} }
func testFac(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) { func testFac(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {

View File

@@ -0,0 +1,68 @@
package adhoc
import (
"sync"
"testing"
"github.com/tetratelabs/wazero"
)
func TestJITConcurrency(t *testing.T) {
if !wazero.JITSupported {
t.Skip()
}
runAdhocTestsUnderHighConcurrency(t, wazero.NewRuntimeConfigJIT)
// TODO: Add conccurent instantiation, invocation and release on a single store test case in https://github.com/tetratelabs/wazero/issues/293
}
func TestInterpreterConcurrency(t *testing.T) {
runAdhocTestsUnderHighConcurrency(t, wazero.NewRuntimeConfigInterpreter)
// TODO: Add conccurent instantiation, invocation and release on a single store test case in https://github.com/tetratelabs/wazero/issues/293
}
func runAdhocTestsUnderHighConcurrency(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
t.Run("huge stack", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testHugeStack)
})
t.Run("fibonacci", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testFibonacci)
})
t.Run("fac", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testFac)
})
t.Run("unreachable", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testUnreachable)
})
t.Run("memory", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testMemory)
})
t.Run("recursive entry", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testRecursiveEntry)
})
t.Run("imported-and-exported func", func(t *testing.T) {
t.Parallel()
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testImportedAndExportedFunc)
})
}
// runAdhocTestUnderHighConcurrency runs a test case in adhoc_test.go with multiple goroutines.
func runAdhocTestUnderHighConcurrency(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig,
adhocTest func(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig)) {
const goroutinesPerCase = 1000
var wg sync.WaitGroup
wg.Add(goroutinesPerCase)
for i := 0; i < goroutinesPerCase; i++ {
go func() {
defer wg.Done()
adhocTest(t, newRuntimeConfig)
}()
}
wg.Wait()
}