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
const JITSupported = true
// NewRuntimeConfig returns NewRuntimeConfigJIT
func NewRuntimeConfig() *RuntimeConfig {
return NewRuntimeConfigJIT()

View File

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

View File

@@ -5,8 +5,6 @@ import (
_ "embed"
"fmt"
"math"
"runtime"
"sync"
"testing"
"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.
var ctx = context.Background()
func TestJIT(t *testing.T) {
if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" {
func TestJITAdhoc(t *testing.T) {
if !wazero.JITSupported {
t.Skip()
}
runTests(t, wazero.NewRuntimeConfigJIT)
runAdhocTests(t, wazero.NewRuntimeConfigJIT)
}
func TestInterpreter(t *testing.T) {
runTests(t, wazero.NewRuntimeConfigInterpreter)
func TestInterpreterAdhoc(t *testing.T) {
runAdhocTests(t, wazero.NewRuntimeConfigInterpreter)
}
var (
@@ -45,7 +43,7 @@ var (
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) {
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) {
// 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())
module, err := r.NewModuleFromSource(hugestackWasm)
require.NoError(t, err)
fn := module.Function("main")
require.NotNil(t, fn)
var wg sync.WaitGroup
wg.Add(goroutines)
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) {
// 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())
module, err := r.NewModuleFromSource(fibWasm)
require.NoError(t, err)
@@ -109,17 +90,9 @@ func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig)
fib := module.Function("fib")
require.NotNil(t, fib)
var wg sync.WaitGroup
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
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) {

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